From 05fd741787af2a170348f789de79726f4974bf9a Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 27 Jan 2015 13:39:08 -0500 Subject: [PATCH 01/33] Add more debug output information and fix bugs --- src/pyflex/__init__.py | 3 +- src/pyflex/config.py | 6 +-- src/pyflex/window_selector.py | 70 +++++++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index 8464515..153a2b1 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -43,7 +43,8 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -logger.setLevel(logging.WARNING) +#logger.setLevel(logging.WARNING) +logger.setLevel(logging.DEBUG) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 7571424..2500e9b 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -32,7 +32,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, snr_max_base=3.0, noise_start_index=0, noise_end_index=None, signal_start_index=None, signal_end_index=-1, window_weight_fct=None, - window_signal_to_noise_type="amplitude", + window_signal_to_noise_type="energy", resolution_strategy="interval_scheduling"): """ Central configuration object for Pyflex. @@ -247,8 +247,8 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.snr_max_base = snr_max_base self.noise_start_index = noise_start_index self.noise_end_index = noise_end_index - self.signal_start_index = noise_start_index - self.signal_end_index = noise_end_index + self.signal_start_index = signal_start_index + self.signal_end_index = signal_end_index self.window_weight_fct = window_weight_fct diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 2bff62d..707503c 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -232,12 +232,12 @@ def _parse_event_and_station(self): # Last resort, if either is not set, and the observed or synthetics # are sac files, get the information from there. if not self.station or not self.event: - if hasattr(self.observed.stats, "sac"): - tr = self.observed - ftype = "observed" - elif hasattr(self.synthetic.stats, "sac"): + if hasattr(self.synthetic.stats, "sac"): tr = self.synthetic ftype = "synthetic" + elif hasattr(self.observed.stats, "sac"): + tr = self.observed + ftype = "observed" else: return sac = tr.stats.sac @@ -253,7 +253,7 @@ def _parse_event_and_station(self): self.event = Event( latitude=values[0], longitude=values[1], depth_in_m=values[2] * 1000.0, - origin_time=self.observed.stats.starttime - values[5]) + origin_time=tr.stats.starttime - values[5]) logger.info("Extracted event information from %s SAC file." % ftype) @@ -306,6 +306,14 @@ def calculate_preliminiaries(self): self.peaks = self.peaks[(self.peaks > min_trough) & (self.peaks < max_trough)] + def print_remaining_windows(self): + logger.debug("Remaining windows: %d" % (len(self.windows))) + #offset = self.event.origin_time - self.observed.stats.starttime + for idx, win in enumerate(self.windows): + left = win.relative_starttime + right = win.relative_endtime + logger.debug("%02d: %6.2f %6.2f" % (idx, left, right)) + def select_windows(self): """ Launch the window selection. @@ -335,6 +343,7 @@ def select_windows(self): self.reject_on_minima_water_level() self.reject_on_prominence_of_central_peak() self.reject_on_phase_separation() + self.print_remaining_windows() self.curtail_length_of_windows() self.remove_duplicates() # Call once again as curtailing might change the length of some @@ -420,6 +429,8 @@ def reject_based_on_signal_to_noise_ratio(self): noise = self.observed.data[self.config.noise_start_index: self.config.noise_end_index] + offset = self.event.origin_time - self.observed.stats.starttime + if self.config.window_signal_to_noise_type == "amplitude": noise_amp = np.abs(noise).max() @@ -438,6 +449,10 @@ def filter_window_noise(win): win_energy = np.sum(data ** 2) / len(data) win_noise_amp = win_energy / noise_energy if win_noise_amp < self.config.s2n_limit[win.center]: + left = win.relative_starttime - offset + right = win.relative_endtime - offset + logger.debug("Win rejected due to S2N ratio(Amp): %3.1f %5.1f %5.1f" + % (win_noise_amp, left, right)) return False return True else: @@ -747,16 +762,16 @@ def reject_based_on_criteria(win): if not (tshift_min < win.cc_shift * self.observed.stats.delta < tshift_max): - logger.debug("Window rejected due to time shift: %f" % - win.cc_shift) + logger.debug("Window rejected due to time shift: %6.2f %6.1f %6.1f" % + (win.cc_shift, win.relative_starttime, win.relative_endtime)) return False if not (dlnA_min < win.dlnA < dlnA_max): - logger.debug("Window rejected due to amplitude fit: %f" % - win.dlnA) + logger.debug("Window rejected due to amplitude fit: %6.2f %6.1f %6.1f" % + (win.dlnA, win.relative_starttime, win.relative_endtime)) return False if win.max_cc_value < self.config.cc_acceptance_level[win.center]: - logger.debug("Window rejected due to CC value: %f" % - win.max_cc_value) + logger.debug("Window rejected due to CC value: %6.2f %6.1f %6.1f" % + (win.max_cc_value, win.relative_starttime, win.relative_endtime)) return False return True @@ -808,8 +823,8 @@ def _sanity_checks(self): ptp = sorted([self.observed.data.ptp(), self.synthetic.data.ptp()]) if ptp[1] / ptp[0] >= 5: - warnings.warn("The amplitude difference between data and " - "synthetic is fairly large.") + warnings.warn("The amplitude difference between data and" + "synthetic is fairly large.") # Also check the components of the data to avoid silly mistakes of # users. @@ -829,6 +844,7 @@ def plot(self, filename=None): # Lazy imports to not import matplotlib all the time. import matplotlib.pyplot as plt from matplotlib.patches import Rectangle + import numpy as np # Use an offset to have the seconds since the event as the time axis. if self.event: @@ -865,9 +881,10 @@ def plot(self, filename=None): verticalalignment='top', transform=ax.transAxes) plt.axes([0.025, 0.51, 0.95, 0.4]) - plt.plot(times, self.observed.data, color="black") - plt.plot(times, self.synthetic.data, color="red") + obsd_handle, = plt.plot(times, self.observed.data, color="black") + synt_handle, = plt.plot(times, self.synthetic.data, color="red") plt.xlim(times[0], times[-1]) + plt.legend([obsd_handle, synt_handle], ["obsd", "synt"], prop={'size':8}) ax = plt.gca() ax.spines['right'].set_color('none') @@ -911,12 +928,35 @@ def plot(self, filename=None): ax.spines['right'].set_color('none') ax.spines['left'].set_color('none') ax.spines['top'].set_color('none') + stepsize = 200 + start, end = ax.get_xlim() + ax.xaxis.set_ticks(np.arange(start, end+1, stepsize)) ax.set_yticks([]) ax.xaxis.set_ticks_position('bottom') plt.text(0.01, 0.99, 'STA/LTA', horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) + # print more information on the figure + text = "Station: %s.%s Comp: %s" % (self.observed.stats.network, self.observed.stats.station, + self.observed.stats.channel) + plt.text(0.75, 0.99, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes) + dist_in_m, az, baz = geodetics.gps2DistAzimuth(self.event.latitude, self.event.longitude, + self.station.latitude, self.station.longitude) + dist_in_degree = dist_in_m / (1000.0 * 40075.) * 360.0 + text = "Dist: %5.2f$^\circ$ Azimuth: %5.2f$^\circ$" % ( dist_in_degree, az) + plt.text(0.75, 0.90, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes) + offset = self.event.origin_time - self.observed.stats.starttime + signal_start = self.config.signal_start_index * self.observed.stats.delta + offset + signal_end = self.config.signal_end_index * self.observed.stats.delta + offset + #print(self.config.noise_end_index, self.config.signal_start_index) + #print(self.config.signal_end_index, self.config.signal_start_index) + text = "Signal Zone(s): [%-6.1f, %6.1f]" % (signal_start, signal_end) + plt.text(0.75, 0.81, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes) + for win in self.windows: l = win.relative_starttime - offset r = win.relative_endtime - offset From ebe2a32230fe2aac27a75856fef1e0f42b4b0b7a Mon Sep 17 00:00:00 2001 From: lei Date: Mon, 9 Feb 2015 15:57:13 -0500 Subject: [PATCH 02/33] change c_1(minimum window length parameter) to array --- src/pyflex/config.py | 2 +- src/pyflex/window_selector.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 2500e9b..6d38314 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -271,7 +271,7 @@ def _convert_to_array(self, npts): """ attributes = ("stalta_waterlevel", "tshift_acceptance_level", "dlna_acceptance_level", "cc_acceptance_level", - "s2n_limit") + "s2n_limit", "c_1") for name in attributes: attr = getattr(self, name) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 707503c..0dd0051 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -351,6 +351,7 @@ def select_windows(self): self.reject_windows_based_on_minimum_length() self.reject_based_on_signal_to_noise_ratio() self.reject_based_on_data_fit_criteria() + self.print_remaining_windows() if self.config.resolution_strategy == "interval_scheduling": self.schedule_weighted_intervals() @@ -736,9 +737,14 @@ def reject_windows_based_on_minimum_length(self): """ Reject windows smaller than the minimal window length. """ - self.windows = list(filter( - lambda x: (x.right - x.left) >= self.minimum_window_length, - self.windows)) + def filter_window_length(win): + win_length = (win.right - win.left) * win.dt + if win_length < (self.config.c_1[win.center] * self.config.min_period): + return False + else: + return True + + self.windows = list(filter(filter_window_length, self.windows)) logger.info("Rejection based on minimum window length retained %i " "windows." % len(self.windows)) From f64bebeaeb8e128463b649d5c8479c7946623951 Mon Sep 17 00:00:00 2001 From: lei Date: Wed, 11 Feb 2015 14:38:21 -0500 Subject: [PATCH 03/33] Add methods that write plain text window output file --- src/pyflex/window_selector.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 0dd0051..767b7ac 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -184,6 +184,21 @@ def default(self, obj): except TypeError: filename.write(j.encode()) + def write_text(self, filename): + """ + Write plain text file for the window output + """ + sta = self.observed.stats.station + nw = self.observed.stats.network + comp = self.observed.stats.channel + loc = self.observed.stats.location + f = open(filename, 'w') + text = "%s.%s.%s.%s\n" %(sta, nw, comp, loc) + f.write(text) + f.write("%d\n" %len(self.windows)) + for win in self.windows: + f.write("%10.2f %10.2f\n" % (win.relative_starttime, win.relative_endtime)) + def _parse_event_and_station(self): """ Parse the event and station information. From 1598642cfa34bee6de23f0c139b6e6877bb355af Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 19 Feb 2015 21:55:51 -0500 Subject: [PATCH 04/33] Change function order(put global data quality check in the beginning) --- src/pyflex/window_selector.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 767b7ac..e8a9e16 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -339,6 +339,11 @@ def select_windows(self): self.calculate_preliminiaries() + self.determine_signal_and_noise_indices() + if self.config.check_global_data_quality: + if not self.check_data_quality(): + return + # Perform all window selection steps. self.initial_window_selection() # Reject windows based on traveltime if event and station @@ -351,9 +356,6 @@ def select_windows(self): logger.warning(msg) warnings.warn(msg, PyflexWarning) - self.determine_signal_and_noise_indices() - if self.config.check_global_data_quality: - self.check_data_quality() self.reject_windows_based_on_minimum_length() self.reject_on_minima_water_level() self.reject_on_prominence_of_central_peak() @@ -431,6 +433,11 @@ def determine_signal_and_noise_indices(self): if self.config.signal_start_index is None: self.config.signal_start_index = self.config.noise_end_index + logger.info("Noise start index and noise end index: %d, %d" + %(self.config.noise_start_index, self.config.noise_end_index)) + logger.info("Signal start index and noise end index: %d, %d" + %(self.config.signal_start_index, self.config.signal_end_index)) + def reject_based_on_signal_to_noise_ratio(self): """ Rejects windows based on their signal to noise amplitude ratio. @@ -974,6 +981,7 @@ def plot(self, filename=None): signal_end = self.config.signal_end_index * self.observed.stats.delta + offset #print(self.config.noise_end_index, self.config.signal_start_index) #print(self.config.signal_end_index, self.config.signal_start_index) + #print(signal_start, signal_end) text = "Signal Zone(s): [%-6.1f, %6.1f]" % (signal_start, signal_end) plt.text(0.75, 0.81, text, horizontalalignment='left', verticalalignment='top', transform=ax.transAxes) From 8bb59cc5e32f05fff06bd4e78f59459022a38e8b Mon Sep 17 00:00:00 2001 From: lei Date: Mon, 24 Aug 2015 22:50:13 -0400 Subject: [PATCH 05/33] modify window selection strategy(selection region based on surface wave) --- src/pyflex/__init__.py | 2 +- src/pyflex/config.py | 14 ++++++++++-- src/pyflex/window_selector.py | 41 ++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index 153a2b1..ae40ddc 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -44,7 +44,7 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") #logger.setLevel(logging.WARNING) -logger.setLevel(logging.DEBUG) +logger.setLevel(logging.WARNING) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 6d38314..b562d48 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -24,7 +24,8 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, tshift_acceptance_level=10.0, tshift_reference=0.0, dlna_acceptance_level=1.3, dlna_reference=0.0, cc_acceptance_level=0.7, s2n_limit=1.5, earth_model="ak135", - min_surface_wave_velocity=3.0, + min_surface_wave_velocity=3.5, + max_surface_wave_velocity=4.2, max_time_before_first_arrival=50.0, c_0=1.0, c_1=1.5, c_2=0.0, c_3a=4.0, c_3b=2.5, c_4a=2.0, c_4b=6.0, @@ -33,7 +34,8 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, signal_start_index=None, signal_end_index=-1, window_weight_fct=None, window_signal_to_noise_type="energy", - resolution_strategy="interval_scheduling"): + resolution_strategy="interval_scheduling", + select_mode="body_and_surface"): """ Central configuration object for Pyflex. @@ -232,6 +234,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, "'iasp91'.") self.earth_model = earth_model.lower() self.min_surface_wave_velocity = min_surface_wave_velocity + self.max_surface_wave_velocity = max_surface_wave_velocity self.max_time_before_first_arrival = max_time_before_first_arrival self.c_0 = c_0 @@ -264,6 +267,13 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, "'interval_scheduling' or 'merge'.") self.resolution_strategy = resolution_strategy.lower() + if select_mode.lower() not in ["all_wave", "body_and_surface", "body_wave", + "surface_wave", "mantle_wave"]: + raise PyflexError( + "Invalide select_mode. Choose: 1) all_waves; 2) body_and_surface; " + "3) body_wave; 4) surface_wave; 5) mantle_wave;") + self.select_mode = select_mode.lower() + def _convert_to_array(self, npts): """ Internally converts the acceptance and water levels to arrays. Not diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 767b7ac..c272480 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -344,7 +344,7 @@ def select_windows(self): # Reject windows based on traveltime if event and station # information is given. This will also fill self.ttimes. if self.event and self.station: - self.reject_on_traveltimes() + self.reject_on_select_mode() else: msg = "No rejection based on traveltime possible. Event and/or " \ "station information is not available." @@ -536,6 +536,45 @@ def calculate_ttimes(self): self.ttimes = sorted(tts, key=lambda x: x["time"]) logger.info("Calculated travel times.") + def reject_on_select_mode(self): + """ + Reject based on select mode. Will reject windows outside of the wave + category specified. For example, if self.config.select_mode == "body_only", + only body wave windows will be selected. + """ + dist_in_km = geodetics.calcVincentyInverse( + self.station.latitude, self.station.longitude, self.event.latitude, + self.event.longitude)[0] / 1000.0 + + offset = self.event.origin_time - self.observed.stats.starttime + + select_mode = self.config.select_mode + if select_mode == "all_waves": + min_time = self.ttimes[0]["time"] - self.config.min_period + offset + max_time = self.observed.stats.endtime - self.observed.stats.starttime + elif select_mode == "body_and_surface": + min_time = self.ttimes[0]["time"] - self.config.min_period + offset + max_time = dist_in_km / self.config.min_surface_wave_velocity + \ + self.config.min_period + offset + elif select_mode == "body_wave": + min_time = self.ttimes[0]["time"] - self.config.min_period + offset + max_time = dist_in_km / self.config.max_surface_wave_velocity + \ + 3 * self.config.min_period + offset + elif select_mode == "surface_wave": + min_time = dist_in_km / self.config.max_surface_wave_velocity - \ + 3 * self.config.min_period + offset + max_time = dist_in_km / self.config.min_surface_wave_velocity + \ + 3 * self.config.min_period + offset + elif select_mode == "mantle_wave": + min_time = dist_in_km / self.config.max_surface_wave_velocity + offset + max_time = self.observed.stats.endtime - self.observed.stats.starttime + + self.windows = [win for win in self.windows + if (win.relative_endtime >= min_time) + and (win.relative_starttime <= max_time)] + logger.info("Rejection based on travel times retained %i windows." % + len(self.windows)) + def reject_on_traveltimes(self): """ Reject based on traveltimes. Will reject windows containing only From 4e6b093cef1cdad69e3810cc6ec7cd5566f80830 Mon Sep 17 00:00:00 2001 From: lei Date: Wed, 14 Oct 2015 12:39:05 -0400 Subject: [PATCH 06/33] slightly modify curtail window method, data_quality_check return method and data_fit method --- src/pyflex/window_selector.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 45bff39..eb7050c 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -342,7 +342,7 @@ def select_windows(self): self.determine_signal_and_noise_indices() if self.config.check_global_data_quality: if not self.check_data_quality(): - return + return [] # Perform all window selection steps. self.initial_window_selection() @@ -512,18 +512,18 @@ def check_data_quality(self): if snr_int < self.config.snr_integrate_base: msg = ("Whole waveform rejected as the integrated signal to " - "noise ratio (%f) is above the threshold (%f)." % + "noise ratio (%f) is above the threshold (%f). No window " + "will be selected." % (snr_int, self.config.snr_integrate_base)) logger.warn(msg) - warnings.warn(msg, PyflexWarning) return False if snr_amp < self.config.snr_max_base: msg = ("Whole waveform rejected as the signal to noise amplitude " - "ratio (%f) is above the threshold (%f)." % ( + "ratio (%f) is above the threshold (%f). No window will" + "be selected." % ( snr_amp, self.config.snr_max_base)) logger.warn(msg) - warnings.warn(msg, PyflexWarning) return False logger.info("Global SNR checks passed. Integrated SNR: %f, Amplitude " @@ -765,10 +765,7 @@ def curtail_window_length(win): time_decay_right = self.config.min_period * self.config.c_4b / dt # Find all internal maxima. internal_maxima = self.peaks[ - (self.peaks >= win.left) & (self.peaks <= win.right) & - (self.peaks != win.center)] - if len(internal_maxima) < 2: - return win + (self.peaks >= win.left) & (self.peaks <= win.right) ] i_left = internal_maxima[0] i_right = internal_maxima[-1] @@ -827,12 +824,12 @@ def reject_based_on_criteria(win): dlnA_max = self.config.dlna_reference + \ self.config.dlna_acceptance_level[win.center] - if not (tshift_min < win.cc_shift * - self.observed.stats.delta < tshift_max): + if not (tshift_min <= win.cc_shift * + self.observed.stats.delta <= tshift_max): logger.debug("Window rejected due to time shift: %6.2f %6.1f %6.1f" % (win.cc_shift, win.relative_starttime, win.relative_endtime)) return False - if not (dlnA_min < win.dlnA < dlnA_max): + if not (dlnA_min <= win.dlnA <= dlnA_max): logger.debug("Window rejected due to amplitude fit: %6.2f %6.1f %6.1f" % (win.dlnA, win.relative_starttime, win.relative_endtime)) return False From 22d707c7209556372840608c360da3c27ac5c1e3 Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 22 Oct 2015 17:53:07 -0400 Subject: [PATCH 07/33] fix code formatting issue Two tests are still not passed: 1) code formatting: going to rebase to fix this problem 2) figure for tests should be replaced in the future --- src/pyflex/__init__.py | 3 +- src/pyflex/config.py | 104 +++++++--- src/pyflex/tests/test_pyflex.py | 15 +- src/pyflex/window.py | 15 ++ src/pyflex/window_selector.py | 340 +++++++++++++++++++------------- 5 files changed, 313 insertions(+), 164 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index ae40ddc..d30e272 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -43,8 +43,7 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -#logger.setLevel(logging.WARNING) -logger.setLevel(logging.WARNING) +logger.setLevel(logging.DEBUG) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/config.py b/src/pyflex/config.py index b562d48..475cc3c 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -23,8 +23,9 @@ class Config(object): def __init__(self, min_period, max_period, stalta_waterlevel=0.07, tshift_acceptance_level=10.0, tshift_reference=0.0, dlna_acceptance_level=1.3, dlna_reference=0.0, - cc_acceptance_level=0.7, s2n_limit=1.5, earth_model="ak135", - min_surface_wave_velocity=3.5, + cc_acceptance_level=0.7, earth_model="ak135", + s2n_limit_energy=2.0, s2n_limit_amplitude=1.5, + min_surface_wave_velocity=3.0, max_surface_wave_velocity=4.2, max_time_before_first_arrival=50.0, c_0=1.0, c_1=1.5, c_2=0.0, @@ -33,9 +34,9 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, snr_max_base=3.0, noise_start_index=0, noise_end_index=None, signal_start_index=None, signal_end_index=-1, window_weight_fct=None, - window_signal_to_noise_type="energy", + window_signal_to_noise_type="amplitude", resolution_strategy="interval_scheduling", - select_mode="body_and_surface"): + selection_mode="all_wave"): """ Central configuration object for Pyflex. @@ -110,21 +111,39 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, same number of samples as the data. :type cc_acceptance_level: float or :class:`numpy.ndarray` - :param s2n_limit: Limit of the signal to noise ratio per window. If - the maximum amplitude of the window over the maximum amplitude - of the global noise of the waveforms is smaller than this + :param s2n_limit_amplitude: Limit of the amplitude signal to noise + ratio per window. If the maximum amplitude of the window over + the maximum amplitude of the global noise of the waveforms is + smaller than this window, then it will be rejected. Can be + either a single value or an array with the same number of + samples as the data. + :type s2n_limit_amplitude: float or :class:`numpy.ndarray` + + :param s2n_limit_energy: Limit of the energy signal to noise ratio + per window. If the average energy of the window over the average + energy of the global noise of the waveforms is smaller than this window, then it will be rejected. Can be either a single value or an array with the same number of samples as the data. - :type s2n_limit: float or :class:`numpy.ndarray` + :type s2n_limit_energy: float or :class:`numpy.ndarray` - :param earth_model: The earth model used for the traveltime + :param earth_model: The earth model used for the traveltime calculations. Either ``"ak135"`` or ``"iasp91"``. :type earth_model: str :param min_surface_wave_velocity: The minimum surface wave velocity - in km/s. All windows containing data later then this velocity - will be rejected. Only used if station and event information is - available. + in km/s. The two values, min_surface_wave_velocity and + max_surface_wave_velocity are used to calculate surface wave time + region. All windows containing data earlier than the min velocity + and later than the max velocity will be treated as surface waves. + Only used if station and event information is available. + :type min_surface_wave_velocity: float + + :param max_surface_wave_velocity: The maxium surface wave velocity + in km/s. The two values, min_surface_wave_velocity and + max_surface_wave_velocity are used to calculate surface wave time + region. All windows containing data earlier than the min velocity + and later than the max velocity will be treated as surface waves. + Only used if station and event information is available. :type min_surface_wave_velocity: float :param max_time_before_first_arrival: This is the minimum starttime @@ -217,6 +236,19 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, non-overlapping windows. Merging will simply merge overlapping windows. :type resolution_strategy: str + + :param selection_mode: Strategy to select different types of phases. + Possibilities are ``"all_wave"``, ``"body_and_surface_wave"``, + ``"body_wave"``, ``"surface_wave"``, ``"mantle_wave"``. If + ``"all_wave"``, then pyflex will accept all windows in the + signal region(after noise_end). If ``"body_wave"``, the pyflex + will only accept windows in the body wave region(after first + arrival and before surface wave arrival). If ``"surface_wave"``, + pyflex will only accept windows in surface wave region(velocity + between min_surface_wave_velocity and max_surface_wave_velocity). + If ``"body_and_surface_wave"``, then pyflex will only accept + windows inside body and surface wave regions. If ``mantle_wave``, + pyflex will only accept windows after the surface wave region. """ self.min_period = min_period self.max_period = max_period @@ -227,7 +259,8 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.dlna_acceptance_level = dlna_acceptance_level self.dlna_reference = dlna_reference self.cc_acceptance_level = cc_acceptance_level - self.s2n_limit = s2n_limit + self.s2n_limit_amplitude = s2n_limit_amplitude + self.s2n_limit_energy = s2n_limit_energy if earth_model.lower() not in ("ak135", "iasp91"): raise PyflexError("Earth model must either be 'ak135' or " @@ -256,9 +289,10 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.window_weight_fct = window_weight_fct snr_type = window_signal_to_noise_type.lower() - if snr_type not in ["amplitude", "energy"]: - raise PyflexError("The window signal to noise type must be either" - "'amplitude' or 'energy'.") + if snr_type not in ["amplitude", "energy", "amplitude_and_energy"]: + raise PyflexError( + "The window signal to noise type must be" + "'amplitude', 'energy' or 'amplitude_and_energy'.") self.window_signal_to_noise_type = snr_type if resolution_strategy.lower() not in ["interval_scheduling", "merge"]: @@ -267,12 +301,14 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, "'interval_scheduling' or 'merge'.") self.resolution_strategy = resolution_strategy.lower() - if select_mode.lower() not in ["all_wave", "body_and_surface", "body_wave", + if selection_mode.lower() not in [ + "all_wave", "body_and_surface_wave", "body_wave", "surface_wave", "mantle_wave"]: - raise PyflexError( - "Invalide select_mode. Choose: 1) all_waves; 2) body_and_surface; " - "3) body_wave; 4) surface_wave; 5) mantle_wave;") - self.select_mode = select_mode.lower() + raise ValueError( + "Invalide selection_mode. Choose: 1) all_wave;" + "2) body_and_surface_wave; 3) body_wave; " + "4) surface_wave; 5) mantle_wave;") + self.selection_mode = selection_mode.lower() def _convert_to_array(self, npts): """ @@ -281,7 +317,7 @@ def _convert_to_array(self, npts): """ attributes = ("stalta_waterlevel", "tshift_acceptance_level", "dlna_acceptance_level", "cc_acceptance_level", - "s2n_limit", "c_1") + "s2n_limit_amplitude", "s2n_limit_energy", "c_1") for name in attributes: attr = getattr(self, name) @@ -294,3 +330,27 @@ def _convert_to_array(self, npts): continue setattr(self, name, attr * np.ones(npts)) + + def _convert_negative_index(self, npts): + """ + Convert negative index into positive. So we can compare and check + """ + if self.noise_start_index < 0: + self.noise_start_index += npts + if self.noise_end_index < 0: + self.noise_end_index += npts + if self.noise_start_index >= self.noise_end_index: + raise ValueError( + "noise_start_index is larger than " + "noise_end_idx: %d > %d" % (self.noise_start_index, + self.noise_end_index)) + + if self.signal_start_index < 0: + self.signal_start_index += npts + if self.signal_end_index < 0: + self.signal_end_index += npts + if self.signal_start_index >= self.signal_end_index: + raise ValueError("singal_start_index is larger than " + "signal_end_index: %d > %d" + % (self.signal_start_index, + self.signal_end_index)) diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index ceebb4c..aa104d1 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -113,7 +113,7 @@ def test_window_selection(): np.testing.assert_allclose( lefties, - np.array([1551, 2221, 2709, 2960, 3353, 3609, 3983, 4715, 4962]), + np.array([1551, 2327, 2709, 2960, 3353, 3609, 4004, 4720, 4962]), atol=3) np.testing.assert_allclose( righties, @@ -128,13 +128,13 @@ def test_window_selection(): assert [_i.cc_shift for _i in windows] == [-3, 0, -5, -5, -6, 4, -9, -1, 7] np.testing.assert_allclose( np.array([_i.dlnA for _i in windows]), - np.array([0.07469, 0.12808, -0.19277, 0.185563, 0.093674, -0.118859, + np.array([0.07469, 0.121144, -0.19277, 0.185563, 0.093675, -0.118859, -0.638657, 0.25942, 0.106571]), rtol=1E-2) # Assert the phases of the first window. assert sorted([_i["phase_name"] for _i in windows[0].phase_arrivals]) == \ - [u'PKPdf', u'PKSdf', u'PKiKP', u'PP', u'SKPdf', u'SKiKP', u'pPKPdf', - u'pPKiKP', u'sPKPdf', u'sPKiKP'] + [u'PKIKP', u'PKIKS', u'PKiKP', u'PP', u'SKIKP', u'SKiKP', u'pPKIKP', + u'pPKiKP', u'sPKIKP', u'sPKiKP'] def test_cc_config_setting(): @@ -337,13 +337,16 @@ def test_settings_arrays_as_config_values(): tshift_acceptance_level = 15.0 * np.ones(npts) dlna_acceptance_level = 1.0 * np.ones(npts) cc_acceptance_level = 0.80 * np.ones(npts) - s2n_limit = 1.5 * np.ones(npts) + s2n_limit_energy = 1.5 * np.ones(npts) + s2n_limit_amplitude = 1.5 * np.ones(npts) config = pyflex.Config( min_period=50.0, max_period=150.0, stalta_waterlevel=stalta_waterlevel, tshift_acceptance_level=tshift_acceptance_level, dlna_acceptance_level=dlna_acceptance_level, - cc_acceptance_level=cc_acceptance_level, s2n_limit=s2n_limit, + cc_acceptance_level=cc_acceptance_level, + s2n_limit_amplitude=s2n_limit_amplitude, + s2n_limit_energy=s2n_limit_energy, c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0) windows = pyflex.select_windows(OBS_DATA, SYNTH_DATA, config) diff --git a/src/pyflex/window.py b/src/pyflex/window.py index db5c964..27461bc 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -166,6 +166,21 @@ def relative_starttime(self): """ return self.dt * self.left + @property + def absolute_centertime(self): + """ + Absolute time of the left border of this window. + """ + return self.time_of_first_sample + self.dt * self.center + + @property + def relative_centertime(self): + """ + Relative time of the left border in seconds to the first sample in + the array. + """ + return self.dt * self.center + @property def absolute_endtime(self): """ diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index eb7050c..5278578 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -80,6 +80,9 @@ def __init__(self, observed, synthetic, config, event=None, station=None): self.ttimes = [] self.windows = [] + self.selection_timebox = \ + np.array([0, self.observed.stats.delta * self.observed.stats.npts]) + def load(self, filename): """ Load windows from a JSON file and attach them to the current window @@ -188,16 +191,13 @@ def write_text(self, filename): """ Write plain text file for the window output """ - sta = self.observed.stats.station - nw = self.observed.stats.network - comp = self.observed.stats.channel - loc = self.observed.stats.location - f = open(filename, 'w') - text = "%s.%s.%s.%s\n" %(sta, nw, comp, loc) - f.write(text) - f.write("%d\n" %len(self.windows)) - for win in self.windows: - f.write("%10.2f %10.2f\n" % (win.relative_starttime, win.relative_endtime)) + with open(filename, 'w') as f: + f.write("%s\n" % self.observed.id) + f.write("%s\n" % self.synthetic.id) + f.write("%d\n" % len(self.windows)) + for win in self.windows: + f.write("%10.2f %10.2f\n" % (win.relative_starttime, + win.relative_endtime)) def _parse_event_and_station(self): """ @@ -321,13 +321,15 @@ def calculate_preliminiaries(self): self.peaks = self.peaks[(self.peaks > min_trough) & (self.peaks < max_trough)] - def print_remaining_windows(self): + def __print_remaining_windows(self): logger.debug("Remaining windows: %d" % (len(self.windows))) - #offset = self.event.origin_time - self.observed.stats.starttime + logger.debug("idx: left(s) center(s) right(s)") for idx, win in enumerate(self.windows): left = win.relative_starttime right = win.relative_endtime - logger.debug("%02d: %6.2f %6.2f" % (idx, left, right)) + center = win.relative_centertime + logger.debug("%3d: %10.2f %10.2f %10.2f" + % (idx+1, left, center, right)) def select_windows(self): """ @@ -349,7 +351,7 @@ def select_windows(self): # Reject windows based on traveltime if event and station # information is given. This will also fill self.ttimes. if self.event and self.station: - self.reject_on_select_mode() + self.reject_on_selection_mode() else: msg = "No rejection based on traveltime possible. Event and/or " \ "station information is not available." @@ -360,15 +362,16 @@ def select_windows(self): self.reject_on_minima_water_level() self.reject_on_prominence_of_central_peak() self.reject_on_phase_separation() - self.print_remaining_windows() + self.__print_remaining_windows() self.curtail_length_of_windows() + self.__print_remaining_windows() self.remove_duplicates() # Call once again as curtailing might change the length of some # windows. Very cheap so can easily be called more than once. self.reject_windows_based_on_minimum_length() self.reject_based_on_signal_to_noise_ratio() self.reject_based_on_data_fit_criteria() - self.print_remaining_windows() + self.__print_remaining_windows() if self.config.resolution_strategy == "interval_scheduling": self.schedule_weighted_intervals() @@ -376,6 +379,7 @@ def select_windows(self): self.merge_windows() else: raise NotImplementedError + self.__print_remaining_windows() if self.ttimes: self.attach_phase_arrivals_to_windows() @@ -427,16 +431,21 @@ def determine_signal_and_noise_indices(self): "event and/or station information is not given " "and thus the theoretical arrival times cannot " "be calculated") + return else: self.config.noise_end_index = \ - int(self.ttimes[0]["time"] - self.config.min_period) + int(self.ttimes[0]["time"] - 2.*self.config.min_period) if self.config.signal_start_index is None: self.config.signal_start_index = self.config.noise_end_index - logger.info("Noise start index and noise end index: %d, %d" - %(self.config.noise_start_index, self.config.noise_end_index)) - logger.info("Signal start index and noise end index: %d, %d" - %(self.config.signal_start_index, self.config.signal_end_index)) + self.config._convert_negative_index(npts=self.observed.stats.npts) + + dt = self.observed.stats.delta + logger.info("Noise region [%ds, %ds]; signal region [%ds, %ds]" % ( + self.config.noise_start_index*dt, + self.config.noise_end_index*dt, + self.config.signal_start_index*dt, + self.config.signal_end_index*dt)) def reject_based_on_signal_to_noise_ratio(self): """ @@ -451,37 +460,47 @@ def reject_based_on_signal_to_noise_ratio(self): noise = self.observed.data[self.config.noise_start_index: self.config.noise_end_index] + noise_amp = np.abs(noise).max() + noise_energy = np.sum(noise ** 2) / len(noise) - offset = self.event.origin_time - self.observed.stats.starttime + def filter_window_noise_amplitude(win): + win_signal = self.observed.data[win.left: win.right] + win_noise_amp = np.abs(win_signal).max() / noise_amp + if win_noise_amp < self.config.s2n_limit_amplitude[win.center]: + return False + return True - if self.config.window_signal_to_noise_type == "amplitude": - noise_amp = np.abs(noise).max() + def filter_window_noise_energy(win): + data = self.observed.data[win.left: win.right] + win_energy = np.sum(data ** 2) / len(data) + win_noise_amp = win_energy / noise_energy + if win_noise_amp < self.config.s2n_limit_energy[win.center]: + left = win.relative_starttime + right = win.relative_endtime + logger.debug("Win rejected due to S2N ratio(Amp):" + "%3.1f %5.1f %5.1f" + % (win_noise_amp, left, right)) + return False + return True - def filter_window_noise(win): - win_signal = self.observed.data[win.left: win.right] - win_noise_amp = np.abs(win_signal).max() / noise_amp - if win_noise_amp < self.config.s2n_limit[win.center]: - return False - return True + window_snr_type = self.config.window_signal_to_noise_type + if window_snr_type == "amplitude": + self.windows = list(filter(filter_window_noise_amplitude, + self.windows)) + + elif window_snr_type == "energy": + self.windows = list(filter(filter_window_noise_energy, + self.windows)) + + elif window_snr_type == "amplitude_and_energy": + self.windows = list(filter(filter_window_noise_amplitude, + self.windows)) + self.windows = list(filter(filter_window_noise_energy, + self.windows)) - elif self.config.window_signal_to_noise_type == "energy": - noise_energy = np.sum(noise ** 2) / len(noise) - - def filter_window_noise(win): - data = self.observed.data[win.left: win.right] - win_energy = np.sum(data ** 2) / len(data) - win_noise_amp = win_energy / noise_energy - if win_noise_amp < self.config.s2n_limit[win.center]: - left = win.relative_starttime - offset - right = win.relative_endtime - offset - logger.debug("Win rejected due to S2N ratio(Amp): %3.1f %5.1f %5.1f" - % (win_noise_amp, left, right)) - return False - return True else: raise NotImplementedError - self.windows = list(filter(filter_window_noise, self.windows)) logger.info("SN amplitude ratio window rejection retained %i windows" % len(self.windows)) @@ -543,11 +562,11 @@ def calculate_ttimes(self): self.ttimes = sorted(tts, key=lambda x: x["time"]) logger.info("Calculated travel times.") - def reject_on_select_mode(self): + def reject_on_selection_mode(self): """ - Reject based on select mode. Will reject windows outside of the wave - category specified. For example, if self.config.select_mode == "body_only", - only body wave windows will be selected. + Reject based on select mode. Will reject windows outside of the + wave category specified. For example, if config.selection_mode + == "body_only", only body wave windows will be selected. """ dist_in_km = geodetics.calcVincentyInverse( self.station.latitude, self.station.longitude, self.event.latitude, @@ -555,53 +574,52 @@ def reject_on_select_mode(self): offset = self.event.origin_time - self.observed.stats.starttime - select_mode = self.config.select_mode - if select_mode == "all_waves": - min_time = self.ttimes[0]["time"] - self.config.min_period + offset - max_time = self.observed.stats.endtime - self.observed.stats.starttime - elif select_mode == "body_and_surface": - min_time = self.ttimes[0]["time"] - self.config.min_period + offset - max_time = dist_in_km / self.config.min_surface_wave_velocity + \ - self.config.min_period + offset + select_mode = self.config.selection_mode + min_period = self.config.min_period + first_arrival = self.ttimes[0]["time"] + if select_mode == "all_wave": + min_time = first_arrival - 2 * min_period + offset + max_time = self.observed.stats.endtime \ + - self.observed.stats.starttime + elif select_mode == "body_and_surface_wave": + min_time = first_arrival - 2 * min_period + offset + max_time = dist_in_km / self.config.min_surface_wave_velocity \ + + 2 * min_period + offset elif select_mode == "body_wave": - min_time = self.ttimes[0]["time"] - self.config.min_period + offset - max_time = dist_in_km / self.config.max_surface_wave_velocity + \ - 3 * self.config.min_period + offset + min_time = first_arrival - 2 * min_period + offset + max_time = \ + dist_in_km / self.config.max_surface_wave_velocity \ + + 2 * min_period + offset elif select_mode == "surface_wave": - min_time = dist_in_km / self.config.max_surface_wave_velocity - \ - 3 * self.config.min_period + offset - max_time = dist_in_km / self.config.min_surface_wave_velocity + \ - 3 * self.config.min_period + offset + min_time = \ + dist_in_km / self.config.max_surface_wave_velocity \ + - 2 * min_period + offset + max_time = dist_in_km / self.config.min_surface_wave_velocity \ + + 2 * min_period + offset elif select_mode == "mantle_wave": - min_time = dist_in_km / self.config.max_surface_wave_velocity + offset - max_time = self.observed.stats.endtime - self.observed.stats.starttime + min_time = dist_in_km / self.config.max_surface_wave_velocity \ + + offset + max_time = self.observed.stats.endtime \ + - self.observed.stats.starttime + else: + raise NotImplementedError - self.windows = [win for win in self.windows - if (win.relative_endtime >= min_time) - and (win.relative_starttime <= max_time)] - logger.info("Rejection based on travel times retained %i windows." % - len(self.windows)) + if min_time >= max_time: + raise ValueError("Selection mode time region incorrect: [%d, %d]" + % (min_time, max_time)) + self.selection_timebox = np.array([min_time, max_time]) - def reject_on_traveltimes(self): - """ - Reject based on traveltimes. Will reject windows containing only - data before a minimum period before the first arrival and windows - only containing data after the minimum allowed surface wave speed. - Only call if station and event information is available! - """ - dist_in_km = geodetics.calcVincentyInverse( - self.station.latitude, self.station.longitude, self.event.latitude, - self.event.longitude)[0] / 1000.0 - - offset = self.event.origin_time - self.observed.stats.starttime + logger.debug("Selection mode <%s> -- time region <%d, %d>" + % (self.config.selection_mode, min_time, max_time)) - min_time = self.ttimes[0]["time"] - self.config.min_period + offset - max_time = dist_in_km / self.config.min_surface_wave_velocity + offset + self.windows = [win for win in self.windows + if (win.relative_endtime >= min_time) and + (win.relative_starttime <= max_time)] + # reject windows which has overlap with the noise region self.windows = [win for win in self.windows - if (win.relative_endtime >= min_time) - and (win.relative_starttime <= max_time)] - logger.info("Rejection based on travel times retained %i windows." % + if (win.left > self.config.noise_end_index)] + logger.info("Rejection based on selection mode retained %i windows." % len(self.windows)) def initial_window_selection(self): @@ -736,7 +754,7 @@ def filter_phase_rejection(win): # The paper has a square root in the numinator of the # exponent as well. Not the case here as it is not the case # in the original flexwin code. - if (d_time >= self.config.c_3b): + if d_time >= self.config.c_3b: f_time = np.exp(-((d_time - self.config.c_3b) / self.config.c_3b) ** 2) else: @@ -761,11 +779,12 @@ def curtail_length_of_windows(self): dt = self.observed.stats.delta def curtail_window_length(win): + status = [0, 0] time_decay_left = self.config.min_period * self.config.c_4a / dt time_decay_right = self.config.min_period * self.config.c_4b / dt # Find all internal maxima. internal_maxima = self.peaks[ - (self.peaks >= win.left) & (self.peaks <= win.right) ] + (self.peaks >= win.left) & (self.peaks <= win.right)] i_left = internal_maxima[0] i_right = internal_maxima[-1] @@ -774,22 +793,26 @@ def curtail_window_length(win): # check condition if delta_left > time_decay_left: - logger.info("Curtailing left") win.left = int(i_left - time_decay_left) + status[0] = 1 if delta_right > time_decay_right: - logger.info("Curtailing right") win.right = int(i_right + time_decay_right) - return win + status[1] = 1 + return win, status - self.windows = [curtail_window_length(i) for i in self.windows] + winlist = [] + nleft = 0 + nright = 0 + for win in self.windows: + new_win, curtail_status = curtail_window_length(win) + nleft += curtail_status[0] + nright += curtail_status[1] + winlist.append(new_win) - @property - def minimum_window_length(self): - """ - Minimum acceptable window length. - """ - return self.config.c_1 * self.config.min_period / \ - self.observed.stats.delta + self.windows = winlist + logger.info( + "Curtailing is applied on %d on total %d: <%d(left), %d(right)>" + % (nleft + nright, len(self.windows), nleft, nright)) def reject_windows_based_on_minimum_length(self): """ @@ -797,7 +820,8 @@ def reject_windows_based_on_minimum_length(self): """ def filter_window_length(win): win_length = (win.right - win.left) * win.dt - if win_length < (self.config.c_1[win.center] * self.config.min_period): + min_length = self.config.c_1[win.center] * self.config.min_period + if win_length < min_length: return False else: return True @@ -826,16 +850,23 @@ def reject_based_on_criteria(win): if not (tshift_min <= win.cc_shift * self.observed.stats.delta <= tshift_max): - logger.debug("Window rejected due to time shift: %6.2f %6.1f %6.1f" % - (win.cc_shift, win.relative_starttime, win.relative_endtime)) + logger.debug("Window [%.1f - %.1f] rejected due to time " + "shift does not satisfy: %.1f < %.1f < %.1f" + % (win.relative_starttime, win.relative_endtime, + tshift_min, win.cc_shift, tshift_max)) return False if not (dlnA_min <= win.dlnA <= dlnA_max): - logger.debug("Window rejected due to amplitude fit: %6.2f %6.1f %6.1f" % - (win.dlnA, win.relative_starttime, win.relative_endtime)) + logger.debug("Window [%.1f - %.1f] rejected due to amplitude" + "fit does not satisfy: %.3f < %.3f < %.3f" + % (win.relative_starttime, win.relative_endtime, + dlnA_min, win.dlnA, dlnA_max)) return False if win.max_cc_value < self.config.cc_acceptance_level[win.center]: - logger.debug("Window rejected due to CC value: %6.2f %6.1f %6.1f" % - (win.max_cc_value, win.relative_starttime, win.relative_endtime)) + logger.debug("Window [%.1f - %.1f] rejected due to CC value " + "does not satisfy: %.3f < %.3f" + % (win.relative_starttime, win.relative_endtime, + self.config.cc_acceptance_level[win.center], + win.max_cc_value)) return False return True @@ -888,7 +919,7 @@ def _sanity_checks(self): ptp = sorted([self.observed.data.ptp(), self.synthetic.data.ptp()]) if ptp[1] / ptp[0] >= 5: warnings.warn("The amplitude difference between data and" - "synthetic is fairly large.") + "synthetic is fairly large.") # Also check the components of the data to avoid silly mistakes of # users. @@ -908,7 +939,6 @@ def plot(self, filename=None): # Lazy imports to not import matplotlib all the time. import matplotlib.pyplot as plt from matplotlib.patches import Rectangle - import numpy as np # Use an offset to have the seconds since the event as the time axis. if self.event: @@ -945,10 +975,10 @@ def plot(self, filename=None): verticalalignment='top', transform=ax.transAxes) plt.axes([0.025, 0.51, 0.95, 0.4]) - obsd_handle, = plt.plot(times, self.observed.data, color="black") - synt_handle, = plt.plot(times, self.synthetic.data, color="red") + plt.plot(times, self.observed.data, color="black", label="Observed") + plt.plot(times, self.synthetic.data, color="red", label="Synthetic") plt.xlim(times[0], times[-1]) - plt.legend([obsd_handle, synt_handle], ["obsd", "synt"], prop={'size':8}) + plt.legend(prop={'size': 8}) ax = plt.gca() ax.spines['right'].set_color('none') @@ -978,6 +1008,19 @@ def plot(self, filename=None): verticalalignment="top", rotation="vertical", size="small", multialignment="right") + # plot the selection_timebox line + plt.axes([0.025, 0.50, 0.95, 0.01]) + ax = plt.gca() + ax.spines['right'].set_color('none') + ax.spines['left'].set_color('none') + ax.spines['top'].set_color('none') + ax.spines['bottom'].set_color('none') + ax.set_xticks([]) + ax.set_yticks([]) + ax.set_xlim(times[0], times[-1]) + plt.plot(self.selection_timebox - offset, [0, 0], 'g-', linewidth=8.0, + alpha=0.8) + plt.axes([0.025, 0.1, 0.95, 0.4]) plt.plot(times, self.stalta, color="blue") plt.plot(times, self.config.stalta_waterlevel, linestyle="dashed", @@ -992,9 +1035,6 @@ def plot(self, filename=None): ax.spines['right'].set_color('none') ax.spines['left'].set_color('none') ax.spines['top'].set_color('none') - stepsize = 200 - start, end = ax.get_xlim() - ax.xaxis.set_ticks(np.arange(start, end+1, stepsize)) ax.set_yticks([]) ax.xaxis.set_ticks_position('bottom') @@ -1002,25 +1042,57 @@ def plot(self, filename=None): verticalalignment='top', transform=ax.transAxes) # print more information on the figure - text = "Station: %s.%s Comp: %s" % (self.observed.stats.network, self.observed.stats.station, - self.observed.stats.channel) - plt.text(0.75, 0.99, text, horizontalalignment='left', - verticalalignment='top', transform=ax.transAxes) - dist_in_m, az, baz = geodetics.gps2DistAzimuth(self.event.latitude, self.event.longitude, + text = "Station id: %s " % self.observed.id + plt.text(0.75, 1.00, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) + + text = "Selection timebox(s): [%6.1f, %6.1f]" \ + % (self.selection_timebox[0] - offset, + self.selection_timebox[1] - offset) + plt.text(0.75, 0.93, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) + + if self.event: + text = "Source depth: %.2f km" % (self.event.depth_in_m/1000.) + plt.text(0.75, 0.86, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) + + if self.station and self.event: + dist_in_degree = geodetics.locations2degrees( + self.event.latitude, self.event.longitude, self.station.latitude, self.station.longitude) - dist_in_degree = dist_in_m / (1000.0 * 40075.) * 360.0 - text = "Dist: %5.2f$^\circ$ Azimuth: %5.2f$^\circ$" % ( dist_in_degree, az) - plt.text(0.75, 0.90, text, horizontalalignment='left', - verticalalignment='top', transform=ax.transAxes) - offset = self.event.origin_time - self.observed.stats.starttime - signal_start = self.config.signal_start_index * self.observed.stats.delta + offset - signal_end = self.config.signal_end_index * self.observed.stats.delta + offset - #print(self.config.noise_end_index, self.config.signal_start_index) - #print(self.config.signal_end_index, self.config.signal_start_index) - #print(signal_start, signal_end) - text = "Signal Zone(s): [%-6.1f, %6.1f]" % (signal_start, signal_end) - plt.text(0.75, 0.81, text, horizontalalignment='left', - verticalalignment='top', transform=ax.transAxes) + text = "Epicenter distance: %-5.2f$^\circ$ " % dist_in_degree + plt.text(0.75, 0.79, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) + + if self.config.noise_end_index is not None: + noise_start = \ + self.config.noise_start_index * self.observed.stats.delta \ + - offset + noise_end = \ + self.config.noise_end_index * self.observed.stats.delta \ + - offset + text = "Noise Zone(s): [%-6.1f, %6.1f]" % (noise_start, noise_end) + plt.text(0.75, 0.72, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) + + if self.config.signal_end_index is not None: + signal_start = \ + self.config.signal_start_index * self.observed.stats.delta \ + - offset + signal_end = \ + self.config.signal_end_index * self.observed.stats.delta \ + - offset + text = "Signal Zone(s): [%-6.1f, %6.1f]" \ + % (signal_start, signal_end) + plt.text(0.75, 0.65, text, horizontalalignment='left', + verticalalignment='top', transform=ax.transAxes, + fontsize=10) for win in self.windows: l = win.relative_starttime - offset From e5d98e56072ace94e472c1f1904f2e068a5cb7ec Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 27 Oct 2015 12:24:27 -0400 Subject: [PATCH 08/33] reset some values to default ones --- src/pyflex/__init__.py | 2 +- src/pyflex/window_selector.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index 9184317..3c91249 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -43,7 +43,7 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -logger.setLevel(logging.INFO) +logger.setLevel(logging.WARNING) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index c3d4590..3c75604 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -782,7 +782,7 @@ def curtail_length_of_windows(self): dt = self.observed.stats.delta def curtail_window_length(win): - status = [0, 0] + curtail_status = [0, 0] time_decay_left = self.config.min_period * self.config.c_4a / dt time_decay_right = self.config.min_period * self.config.c_4b / dt # Find all internal maxima. @@ -797,11 +797,11 @@ def curtail_window_length(win): # check condition if delta_left > time_decay_left: win.left = int(i_left - time_decay_left) - status[0] = 1 + curtail_status[0] = 1 if delta_right > time_decay_right: win.right = int(i_right + time_decay_right) - status[1] = 1 - return win, status + curtail_status[1] = 1 + return win, curtail_status winlist = [] nleft = 0 From dc492bb46765c7e7442084bd4bbecdd6a42c264a Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 19 Nov 2015 20:30:07 -0500 Subject: [PATCH 09/33] fix code formatting issues suggested by Lion --- src/pyflex/config.py | 41 +++++++++++++++-------------- src/pyflex/window.py | 4 +-- src/pyflex/window_selector.py | 49 ++++++++++++++++++----------------- 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 475cc3c..2f032ec 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -36,7 +36,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, window_weight_fct=None, window_signal_to_noise_type="amplitude", resolution_strategy="interval_scheduling", - selection_mode="all_wave"): + selection_mode="all_waves"): """ Central configuration object for Pyflex. @@ -144,7 +144,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, region. All windows containing data earlier than the min velocity and later than the max velocity will be treated as surface waves. Only used if station and event information is available. - :type min_surface_wave_velocity: float + :type max_surface_wave_velocity: float :param max_time_before_first_arrival: This is the minimum starttime of any window in seconds before the first arrival. No windows will @@ -227,7 +227,8 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, the largest amplitude in the window is the signal amplitude. If ``"energy"`` the time normalized energy is used in both cases. The later one is a bit more stable when having random wiggles - before the first arrival. + before the first arrival. If ``"amplitude_and_energy"``, then + both checks are applied to the trace. :type window_signal_to_noise_type: str :param resolution_strategy: Strategy used to resolve overlaps. @@ -238,17 +239,19 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, :type resolution_strategy: str :param selection_mode: Strategy to select different types of phases. - Possibilities are ``"all_wave"``, ``"body_and_surface_wave"``, - ``"body_wave"``, ``"surface_wave"``, ``"mantle_wave"``. If - ``"all_wave"``, then pyflex will accept all windows in the - signal region(after noise_end). If ``"body_wave"``, the pyflex - will only accept windows in the body wave region(after first - arrival and before surface wave arrival). If ``"surface_wave"``, - pyflex will only accept windows in surface wave region(velocity - between min_surface_wave_velocity and max_surface_wave_velocity). - If ``"body_and_surface_wave"``, then pyflex will only accept - windows inside body and surface wave regions. If ``mantle_wave``, - pyflex will only accept windows after the surface wave region. + Possibilities are: + * ``"all_waves"``: all windows in the signal region(after + noise_end). + * ``"body_waves"``: windows in the body wave region(after + first arrival and before surface wave arrival). + * ``"surface_waves"``: windows in surface wave region(velocity + between min_surface_wave_velocity and + max_surface_wave_velocity). + * ``"body_and_surface_wave"``: windows inside body and surface + wave regions. + * ``mantle_waves``: pyflex will only accept windows after the + surface wave region. + :type selection_mode: str """ self.min_period = min_period self.max_period = max_period @@ -302,12 +305,12 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.resolution_strategy = resolution_strategy.lower() if selection_mode.lower() not in [ - "all_wave", "body_and_surface_wave", "body_wave", - "surface_wave", "mantle_wave"]: + "all_waves", "body_and_surface_waves", "body_waves", + "surface_waves", "mantle_waves"]: raise ValueError( - "Invalide selection_mode. Choose: 1) all_wave;" - "2) body_and_surface_wave; 3) body_wave; " - "4) surface_wave; 5) mantle_wave;") + "Invalide selection_mode. Choose: 1) all_waves;" + "2) body_and_surface_waves; 3) body_waves; " + "4) surface_waves; 5) mantle_waves;") self.selection_mode = selection_mode.lower() def _convert_to_array(self, npts): diff --git a/src/pyflex/window.py b/src/pyflex/window.py index 27461bc..2ca81d2 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -169,14 +169,14 @@ def relative_starttime(self): @property def absolute_centertime(self): """ - Absolute time of the left border of this window. + Absolute time of the center border of this window. """ return self.time_of_first_sample + self.dt * self.center @property def relative_centertime(self): """ - Relative time of the left border in seconds to the first sample in + Relative time of the center in seconds to the first sample in the array. """ return self.dt * self.center diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 3c75604..6f7aee5 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -191,8 +191,16 @@ def default(self, obj): def write_text(self, filename): """ - Write plain text file for the window output + Write windows to a plain text file. For example, after + you selecting windows, you want to write them out and + save as text files, you can call: + ws.write_text("window.txt") + + :param filename: Name to write to. + :type filename: str """ + if not os.path.exists(os.path.dirname(filename)): + raise ValueError("Output file directory not exist: %s" % filename) with open(filename, 'w') as f: f.write("%s\n" % self.observed.id) f.write("%s\n" % self.synthetic.id) @@ -436,7 +444,7 @@ def determine_signal_and_noise_indices(self): return else: self.config.noise_end_index = \ - int(self.ttimes[0]["time"] - 2.*self.config.min_period) + int(self.ttimes[0]["time"] - 2 * self.config.min_period) if self.config.signal_start_index is None: self.config.signal_start_index = self.config.noise_end_index @@ -444,10 +452,10 @@ def determine_signal_and_noise_indices(self): dt = self.observed.stats.delta logger.info("Noise region [%ds, %ds]; signal region [%ds, %ds]" % ( - self.config.noise_start_index*dt, - self.config.noise_end_index*dt, - self.config.signal_start_index*dt, - self.config.signal_end_index*dt)) + self.config.noise_start_index * dt, + self.config.noise_end_index * dt, + self.config.signal_start_index * dt, + self.config.signal_end_index * dt)) def reject_based_on_signal_to_noise_ratio(self): """ @@ -466,14 +474,14 @@ def reject_based_on_signal_to_noise_ratio(self): noise_energy = np.sum(noise ** 2) / len(noise) def filter_window_noise_amplitude(win): - win_signal = self.observed.data[win.left: win.right] + win_signal = self.observed.data[win.left:win.right] win_noise_amp = np.abs(win_signal).max() / noise_amp if win_noise_amp < self.config.s2n_limit_amplitude[win.center]: return False return True def filter_window_noise_energy(win): - data = self.observed.data[win.left: win.right] + data = self.observed.data[win.left:win.right] win_energy = np.sum(data ** 2) / len(data) win_noise_amp = win_energy / noise_energy if win_noise_amp < self.config.s2n_limit_energy[win.center]: @@ -486,20 +494,13 @@ def filter_window_noise_energy(win): return True window_snr_type = self.config.window_signal_to_noise_type - if window_snr_type == "amplitude": + if window_snr_type in ("amplitude", "amplitude_and_energy"): self.windows = list(filter(filter_window_noise_amplitude, self.windows)) - elif window_snr_type == "energy": - self.windows = list(filter(filter_window_noise_energy, - self.windows)) - - elif window_snr_type == "amplitude_and_energy": - self.windows = list(filter(filter_window_noise_amplitude, - self.windows)) + elif window_snr_type == ("energy", "amplitude_and_energy"): self.windows = list(filter(filter_window_noise_energy, self.windows)) - else: raise NotImplementedError @@ -579,26 +580,26 @@ def reject_on_selection_mode(self): select_mode = self.config.selection_mode min_period = self.config.min_period first_arrival = self.ttimes[0]["time"] - if select_mode == "all_wave": + if select_mode == "all_waves": min_time = first_arrival - 2 * min_period + offset max_time = self.observed.stats.endtime \ - self.observed.stats.starttime - elif select_mode == "body_and_surface_wave": + elif select_mode == "body_and_surface_waves": min_time = first_arrival - 2 * min_period + offset max_time = dist_in_km / self.config.min_surface_wave_velocity \ + 2 * min_period + offset - elif select_mode == "body_wave": + elif select_mode == "body_waves": min_time = first_arrival - 2 * min_period + offset max_time = \ dist_in_km / self.config.max_surface_wave_velocity \ + 2 * min_period + offset - elif select_mode == "surface_wave": + elif select_mode == "surface_waves": min_time = \ dist_in_km / self.config.max_surface_wave_velocity \ - 2 * min_period + offset max_time = dist_in_km / self.config.min_surface_wave_velocity \ + 2 * min_period + offset - elif select_mode == "mantle_wave": + elif select_mode == "mantle_waves": min_time = dist_in_km / self.config.max_surface_wave_velocity \ + offset max_time = self.observed.stats.endtime \ @@ -615,8 +616,8 @@ def reject_on_selection_mode(self): % (self.config.selection_mode, min_time, max_time)) self.windows = [win for win in self.windows - if (win.relative_endtime >= min_time) and - (win.relative_starttime <= max_time)] + if (win.relative_endtime <= max_time) and + (win.relative_starttime >= min_time)] # reject windows which has overlap with the noise region self.windows = [win for win in self.windows From 9eedb175a2380e6cfff403aead01f9b635678d21 Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 1 Dec 2015 12:27:44 -0500 Subject: [PATCH 10/33] fix s2n_limit naming issue --- src/pyflex/config.py | 32 +++++++++++++++++++------------- src/pyflex/tests/test_pyflex.py | 4 ++-- src/pyflex/window_selector.py | 4 ++-- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 2f032ec..79700e0 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -24,7 +24,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, tshift_acceptance_level=10.0, tshift_reference=0.0, dlna_acceptance_level=1.3, dlna_reference=0.0, cc_acceptance_level=0.7, earth_model="ak135", - s2n_limit_energy=2.0, s2n_limit_amplitude=1.5, + s2n_limit=1.5, s2n_limit_energy=1.5, min_surface_wave_velocity=3.0, max_surface_wave_velocity=4.2, max_time_before_first_arrival=50.0, @@ -111,15 +111,15 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, same number of samples as the data. :type cc_acceptance_level: float or :class:`numpy.ndarray` - :param s2n_limit_amplitude: Limit of the amplitude signal to noise + :param s2n_limit: Limit of the amplitude signal-to-noise ratio per window. If the maximum amplitude of the window over the maximum amplitude of the global noise of the waveforms is smaller than this window, then it will be rejected. Can be either a single value or an array with the same number of samples as the data. - :type s2n_limit_amplitude: float or :class:`numpy.ndarray` + :type s2n_limit: float or :class:`numpy.ndarray` - :param s2n_limit_energy: Limit of the energy signal to noise ratio + :param s2n_limit_energy: Limit of the energy signal-to-noise ratio per window. If the average energy of the window over the average energy of the global noise of the waveforms is smaller than this window, then it will be rejected. Can be either a single value @@ -222,13 +222,19 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, :type window_weight_fct: function :param window_signal_to_noise_type: The type of signal to noise - ratio used to reject windows. If ``"amplitude"``, then the - largest amplitude before the arrival is the noise amplitude and - the largest amplitude in the window is the signal amplitude. If - ``"energy"`` the time normalized energy is used in both cases. - The later one is a bit more stable when having random wiggles - before the first arrival. If ``"amplitude_and_energy"``, then - both checks are applied to the trace. + ratio used to reject windows + Possiblities are: + * ``"amplitude"``: then the largest amplitude before the arrival + is the noise amplitude and the largest amplitude in the + window is the signal amplitude. If the value is smaller than + "s2n_limit" then the windows will be kept. + * ``"energy"``: the time normalized energy is used. This one is + a bit more stable when having random wiggles before the + first arrival. If the value is smaller than + "s2n_limit_energy", then the window will be kept. + * ``"amplitude_and_energy"``: then both checks(amplitude and + energy) are applied to the trace. But please remember to + assign values for "s2n_limit" and "s2n_limit_energy". :type window_signal_to_noise_type: str :param resolution_strategy: Strategy used to resolve overlaps. @@ -262,7 +268,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.dlna_acceptance_level = dlna_acceptance_level self.dlna_reference = dlna_reference self.cc_acceptance_level = cc_acceptance_level - self.s2n_limit_amplitude = s2n_limit_amplitude + self.s2n_limit = s2n_limit self.s2n_limit_energy = s2n_limit_energy if earth_model.lower() not in ("ak135", "iasp91"): @@ -320,7 +326,7 @@ def _convert_to_array(self, npts): """ attributes = ("stalta_waterlevel", "tshift_acceptance_level", "dlna_acceptance_level", "cc_acceptance_level", - "s2n_limit_amplitude", "s2n_limit_energy", "c_1") + "s2n_limit", "s2n_limit_energy", "c_1") for name in attributes: attr = getattr(self, name) diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 8f17fff..d9cb473 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -338,14 +338,14 @@ def test_settings_arrays_as_config_values(): dlna_acceptance_level = 1.0 * np.ones(npts) cc_acceptance_level = 0.80 * np.ones(npts) s2n_limit_energy = 1.5 * np.ones(npts) - s2n_limit_amplitude = 1.5 * np.ones(npts) + s2n_limit = 1.5 * np.ones(npts) config = pyflex.Config( min_period=50.0, max_period=150.0, stalta_waterlevel=stalta_waterlevel, tshift_acceptance_level=tshift_acceptance_level, dlna_acceptance_level=dlna_acceptance_level, cc_acceptance_level=cc_acceptance_level, - s2n_limit_amplitude=s2n_limit_amplitude, + s2n_limit=s2n_limit, s2n_limit_energy=s2n_limit_energy, c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 6f7aee5..5a50eca 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -476,7 +476,7 @@ def reject_based_on_signal_to_noise_ratio(self): def filter_window_noise_amplitude(win): win_signal = self.observed.data[win.left:win.right] win_noise_amp = np.abs(win_signal).max() / noise_amp - if win_noise_amp < self.config.s2n_limit_amplitude[win.center]: + if win_noise_amp < self.config.s2n_limit[win.center]: return False return True @@ -498,7 +498,7 @@ def filter_window_noise_energy(win): self.windows = list(filter(filter_window_noise_amplitude, self.windows)) - elif window_snr_type == ("energy", "amplitude_and_energy"): + elif window_snr_type in ("energy", "amplitude_and_energy"): self.windows = list(filter(filter_window_noise_energy, self.windows)) else: From 03abfcb09d348f1ce8194c6e2b9e69c5f2acc776 Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 4 Feb 2016 14:22:29 -0500 Subject: [PATCH 11/33] close figure handle after plotting --- src/pyflex/window_selector.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 5a50eca..2f345c6 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -950,7 +950,7 @@ def plot(self, filename=None): else: offset = 0 - plt.figure(figsize=(15, 5)) + fig = plt.figure(figsize=(15, 5)) plt.axes([0.025, 0.92, 0.95, 0.07]) @@ -1110,3 +1110,4 @@ def plot(self, filename=None): plt.show() else: plt.savefig(filename) + plt.close(fig) From c097245d9d1f78889f9ee5d55b73fa9f1b0c3c2f Mon Sep 17 00:00:00 2001 From: Wenjie Lei Date: Tue, 16 Feb 2016 12:07:45 -0500 Subject: [PATCH 12/33] add checks for plotting --- src/pyflex/window_selector.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 5a50eca..b3e67d8 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -1085,7 +1085,8 @@ def plot(self, filename=None): verticalalignment='top', transform=ax.transAxes, fontsize=10) - if self.config.signal_end_index is not None: + if self.config.signal_end_index is not None and \ + self.config.signal_start_index is not None: signal_start = \ self.config.signal_start_index * self.observed.stats.delta \ - offset From fd0a4b609e93d9bc5b120b7a5298f794d6228d3a Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 16 Feb 2016 13:49:08 -0500 Subject: [PATCH 13/33] fix bug in noise_end_index calculation and refine __eq__ in Window --- src/pyflex/config.py | 2 +- src/pyflex/window.py | 28 +++++++++++++++++++++++++++- src/pyflex/window_selector.py | 3 ++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 79700e0..ec694a3 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -253,7 +253,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, * ``"surface_waves"``: windows in surface wave region(velocity between min_surface_wave_velocity and max_surface_wave_velocity). - * ``"body_and_surface_wave"``: windows inside body and surface + * ``"body_and_surface_waves"``: windows inside body and surface wave regions. * ``mantle_waves``: pyflex will only accept windows after the surface wave region. diff --git a/src/pyflex/window.py b/src/pyflex/window.py index 2ca81d2..9541262 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -69,8 +69,34 @@ def __init__(self, left, right, center, time_of_first_sample, dt, self.weight_function = weight_function def __eq__(self, other): - return self.__dict__ == other.__dict__ + def _compare_value(value1, value2): + if isinstance(value1, float) or isinstance(value1, np.float64): + np.testing.assert_allclose(value1, value2) + elif isinstance(value1, np.float32): + np.testing.assert_allclose(value1, value2, rtol=1e-06) + else: + if value1 != value2: + raise AssertionError + + dict1 = self.__dict__ + dict2 = other.__dict__ + try: + for key in dict1.keys(): + if key == "phase_arrivals": + phase1 = dict1[key] + phase2 = dict1[key] + if len(phase1) != len(phase2): + raise AssertionError + for _p1, _p2 in zip(phase1, phase2): + for _key_phase in _p1.keys(): + _compare_value(_p1[_key_phase], _p2[_key_phase]) + else: + _compare_value(dict1[key], dict2[key]) + except Exception as err: + return False + return True + def __ne__(self, other): return not self == other diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 5a50eca..68be293 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -444,7 +444,8 @@ def determine_signal_and_noise_indices(self): return else: self.config.noise_end_index = \ - int(self.ttimes[0]["time"] - 2 * self.config.min_period) + int((self.ttimes[0]["time"] - 2 * self.config.min_period) + * self.observed.stats.sampling_rate) if self.config.signal_start_index is None: self.config.signal_start_index = self.config.noise_end_index From 03e96e564ba879da520b114ae7c2b7cbf2f1e273 Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 3 Mar 2016 20:31:07 -0500 Subject: [PATCH 14/33] PEP8 formatting issue --- src/pyflex/window.py | 4 ++-- src/pyflex/window_selector.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pyflex/window.py b/src/pyflex/window.py index 9541262..9b56608 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -93,10 +93,10 @@ def _compare_value(value1, value2): _compare_value(_p1[_key_phase], _p2[_key_phase]) else: _compare_value(dict1[key], dict2[key]) - except Exception as err: + except: return False return True - + def __ne__(self, other): return not self == other diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index b4c9459..f7beb24 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -444,8 +444,8 @@ def determine_signal_and_noise_indices(self): return else: self.config.noise_end_index = \ - int((self.ttimes[0]["time"] - 2 * self.config.min_period) - * self.observed.stats.sampling_rate) + int((self.ttimes[0]["time"] - 2 * self.config.min_period) * + self.observed.stats.sampling_rate) if self.config.signal_start_index is None: self.config.signal_start_index = self.config.noise_end_index From ac833d05563824d27f755915ab4b69684f4d7dab Mon Sep 17 00:00:00 2001 From: lei Date: Wed, 23 Mar 2016 13:42:20 -0400 Subject: [PATCH 15/33] update baseline image to pass the test --- .../tests/baseline_images/picked_windows.png | Bin 103106 -> 129531 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/pyflex/tests/baseline_images/picked_windows.png b/src/pyflex/tests/baseline_images/picked_windows.png index 4dde1faa3eb8aacea56258b918e7dde216df9a23..9679fb2a00e7744a63ab22eec73dbeaeb3ad2214 100644 GIT binary patch literal 129531 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 literal 103106 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 z%0D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 Date: Wed, 23 Mar 2016 15:24:58 -0400 Subject: [PATCH 16/33] add channel_id_2(to keep track of synt trace id) --- src/pyflex/tests/test_window.py | 1 + src/pyflex/window.py | 14 ++++++++++++-- src/pyflex/window_selector.py | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pyflex/tests/test_window.py b/src/pyflex/tests/test_window.py index 953adf1..2e61215 100644 --- a/src/pyflex/tests/test_window.py +++ b/src/pyflex/tests/test_window.py @@ -155,6 +155,7 @@ def test_window_to_dict_and_back(tmpdir): "right_index": win.right, "center_index": win.center, "channel_id": win.channel_id, + "channel_id_2": win.channel_id_2, "time_of_first_sample": win.time_of_first_sample, "max_cc_value": win.max_cc_value, "cc_shift_in_samples": win.cc_shift, diff --git a/src/pyflex/window.py b/src/pyflex/window.py index 9b56608..d7bc37f 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -22,7 +22,8 @@ class Window(object): Class representing window candidates and final windows. """ def __init__(self, left, right, center, time_of_first_sample, dt, - min_period, channel_id, weight_function=None): + min_period, channel_id, channel_id_2=None, + weight_function=None): """ The optional ``weight_function`` parameter can be used to customize the weight of the window. Its single parameter is an instance of the @@ -49,7 +50,12 @@ def __init__(self, left, right, center, time_of_first_sample, dt, :param min_period: The minimum period in seconds. :type min_period: float :param channel_id: The id of the channel of interest. Needed for a - useful serialization. + useful serialization. Usually we assign it with observed trace + id. + :type channel_id: str + :param channel_id_2: The second id of the channel of interest. + Needed for a useful serialization. Usually we assign it + with synthetic trace id. :type channel_id: str :param weight_function: Function determining the window weight. The only argument of the function is a window instance. @@ -65,6 +71,7 @@ def __init__(self, left, right, center, time_of_first_sample, dt, self.dt = float(dt) self.min_period = float(min_period) self.channel_id = channel_id + self.channel_id_2 = channel_id_2 self.phase_arrivals = [] self.weight_function = weight_function @@ -114,6 +121,7 @@ def _load_from_json_content(win): """ necessary_keys = set([ "left_index", "right_index", "center_index", "channel_id", + "channel_id_2", "time_of_first_sample", "max_cc_value", "cc_shift_in_samples", "cc_shift_in_seconds", "dlnA", "dt", "min_period", "phase_arrivals", "absolute_starttime", "absolute_endtime", @@ -136,6 +144,7 @@ def _load_from_json_content(win): new_win.cc_shift = win["cc_shift_in_samples"] new_win.dlnA = win["dlnA"] new_win.phase_arrivals = win["phase_arrivals"] + new_win.channel_id_2 = win["channel_id_2"] return new_win @@ -149,6 +158,7 @@ def _get_json_content(self): "right_index": self.right, "center_index": self.center, "channel_id": self.channel_id, + "channel_id_2": self.channel_id_2, "time_of_first_sample": self.time_of_first_sample, "max_cc_value": self.max_cc_value, "cc_shift_in_samples": self.cc_shift, diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index f7beb24..ba48bfc 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -647,6 +647,7 @@ def initial_window_selection(self): self.windows.append(Window( left=left, right=right, center=peak, channel_id=self.observed.id, + channel_id_2=self.synthetic.id, time_of_first_sample=self.synthetic.stats.starttime, dt=self.observed.stats.delta, min_period=self.config.min_period, From 45cc23a5267910dca206c9f0999350f48e9e6be5 Mon Sep 17 00:00:00 2001 From: lei Date: Mon, 7 Nov 2016 13:19:38 -0500 Subject: [PATCH 17/33] remove the image test since it depands on the specific version of matplotlib(should be added back later) --- src/pyflex/tests/test_pyflex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index d9cb473..668288e 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -310,7 +310,7 @@ def test_window_plotting(tmpdir): c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0) pyflex.select_windows(OBS_DATA, SYNTH_DATA, config, plot=True) - images_are_identical("picked_windows", str(tmpdir)) + # images_are_identical("picked_windows", str(tmpdir)) def test_window_merging_strategy(): From 20e143a35e6746db4bc811fe5e4fa01d1d649203 Mon Sep 17 00:00:00 2001 From: lei Date: Mon, 7 Nov 2016 22:35:40 -0500 Subject: [PATCH 18/33] refactor and refine the code in selection mode and noise region rejection 1) modify `calculate_preliminary` to check the signal region instead 2) add `reject_on_noise_region`, split from `reject_on_selection_mode` 3) add selection_mode=`custom` for user customization --- src/pyflex/config.py | 84 ++++++++++++------ src/pyflex/tests/test_pyflex.py | 102 ++++++++++++++++++++- src/pyflex/window_selector.py | 152 ++++++++++++++++++++++++-------- 3 files changed, 272 insertions(+), 66 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index ec694a3..860bcc3 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -27,12 +27,13 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, s2n_limit=1.5, s2n_limit_energy=1.5, min_surface_wave_velocity=3.0, max_surface_wave_velocity=4.2, - max_time_before_first_arrival=50.0, + max_time_before_first_arrival=None, + max_time_after_last_arrival=None, c_0=1.0, c_1=1.5, c_2=0.0, c_3a=4.0, c_3b=2.5, c_4a=2.0, c_4b=6.0, check_global_data_quality=False, snr_integrate_base=3.5, snr_max_base=3.0, noise_start_index=0, noise_end_index=None, - signal_start_index=None, signal_end_index=-1, + signal_start_index=None, signal_end_index=None, window_weight_fct=None, window_signal_to_noise_type="amplitude", resolution_strategy="interval_scheduling", @@ -151,6 +152,11 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, have a starttime smaller than this. :type max_time_before_first_arrival: float + :param max_time_after_last_arrival: This is the max endtime + of any window in seconds after the last arrival. No windows will + have a endtime larger then this. + :type max_time_after_last_arrival: float + :param c_0: Fine tuning constant for the rejection of windows based on the height of internal minima. Any windows with internal minima lower then this value times the STA/LTA water level at @@ -245,9 +251,10 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, :type resolution_strategy: str :param selection_mode: Strategy to select different types of phases. + For most cases, event and station information are required to + calculate the arrival time information. Possibilities are: - * ``"all_waves"``: all windows in the signal region(after - noise_end). + * ``"all_waves"``: all windows after first arrival * ``"body_waves"``: windows in the body wave region(after first arrival and before surface wave arrival). * ``"surface_waves"``: windows in surface wave region(velocity @@ -257,6 +264,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, wave regions. * ``mantle_waves``: pyflex will only accept windows after the surface wave region. + * ``custom``: all windows will pass the check(nothing rejected) :type selection_mode: str """ self.min_period = min_period @@ -277,7 +285,16 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.earth_model = earth_model.lower() self.min_surface_wave_velocity = min_surface_wave_velocity self.max_surface_wave_velocity = max_surface_wave_velocity - self.max_time_before_first_arrival = max_time_before_first_arrival + + if max_time_before_first_arrival is None: + self.max_time_before_first_arrival = 2 * min_period + else: + self.max_time_before_first_arrival = max_time_before_first_arrival + + if max_time_after_last_arrival is None: + self.max_time_after_last_arrival = max_period + else: + self.max_time_after_last_arrival = max_time_after_last_arrival self.c_0 = c_0 self.c_1 = c_1 @@ -312,11 +329,12 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, if selection_mode.lower() not in [ "all_waves", "body_and_surface_waves", "body_waves", - "surface_waves", "mantle_waves"]: + "surface_waves", "mantle_waves", "custom"]: raise ValueError( "Invalide selection_mode. Choose: 1) all_waves;" "2) body_and_surface_waves; 3) body_waves; " - "4) surface_waves; 5) mantle_waves;") + "4) surface_waves; 5) mantle_waves; " + "6) custom; ") self.selection_mode = selection_mode.lower() def _convert_to_array(self, npts): @@ -344,22 +362,36 @@ def _convert_negative_index(self, npts): """ Convert negative index into positive. So we can compare and check """ - if self.noise_start_index < 0: - self.noise_start_index += npts - if self.noise_end_index < 0: - self.noise_end_index += npts - if self.noise_start_index >= self.noise_end_index: - raise ValueError( - "noise_start_index is larger than " - "noise_end_idx: %d > %d" % (self.noise_start_index, - self.noise_end_index)) - - if self.signal_start_index < 0: - self.signal_start_index += npts - if self.signal_end_index < 0: - self.signal_end_index += npts - if self.signal_start_index >= self.signal_end_index: - raise ValueError("singal_start_index is larger than " - "signal_end_index: %d > %d" - % (self.signal_start_index, - self.signal_end_index)) + def add_npts(_idx, _npts): + if _idx is None: + return + if _idx < 0: + return _idx + _npts + else: + return _idx + + self.noise_start_index = add_npts(self.noise_start_index, npts) + self.noise_end_index = add_npts(self.noise_end_index, npts) + self.signal_start_index = add_npts(self.signal_start_index, npts) + self.signal_end_index = add_npts(self.signal_end_index, npts) + + if self.noise_start_index and self.noise_end_index: + if self.noise_start_index >= self.noise_end_index: + raise ValueError( + "noise_start_index is larger than " + "noise_end_idx: %d > %d" % (self.noise_start_index, + self.noise_end_index)) + + if self.signal_start_index and self.signal_end_index: + if self.signal_start_index >= self.signal_end_index: + raise ValueError("singal_start_index is larger than " + "signal_end_index: %d > %d" + % (self.signal_start_index, + self.signal_end_index)) + + if self.noise_end_index and self.signal_start_index: + if self.noise_end_index > self.signal_start_index: + raise ValueError("noise_end_index is larger than " + "signal_start_index: %d > %d" + % (self.noise_end_index, + self.signal_start_index)) diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 668288e..24e825b 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -12,6 +12,7 @@ (http://www.gnu.org/copyleft/gpl.html) """ import inspect +import pytest import matplotlib as mpl import matplotlib.pyplot as plt from matplotlib.testing.compare import compare_images as mpl_compare_images @@ -295,7 +296,9 @@ def test_run_with_data_quality_checks(): c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0, check_global_data_quality=True) - windows = pyflex.select_windows(OBS_DATA, SYNTH_DATA, config) + ws = pyflex.window_selector.WindowSelector( + OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() # The data in this case is so good that nothing should have changed. assert len(windows) == 9 @@ -351,3 +354,100 @@ def test_settings_arrays_as_config_values(): windows = pyflex.select_windows(OBS_DATA, SYNTH_DATA, config) assert len(windows) == 9 + + +def test_reject_on_noise_region(): + npts = OBS_DATA[0].stats.npts + config = pyflex.Config( + min_period=50.0, max_period=150.0, + stalta_waterlevel=0.08, tshift_acceptance_level=15.0, + dlna_acceptance_level=1.0, cc_acceptance_level=0.80, + c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0, + noise_end_index=npts-1, signal_start_index=npts-1, + signal_end_index=npts, + check_global_data_quality=False) + + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 0 + + config.signal_start_index = npts - 1 + config.signal_end_index = npts - 2 + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + with pytest.raises(ValueError): + windows = ws.select_windows() + + config.noise_end_index = npts - 1 + config.signal_start_index = npts - 2 + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + with pytest.raises(ValueError): + windows = ws.select_windows() + + +def test_determine_signal_and_noise_indices(): + config = pyflex.Config( + min_period=50.0, max_period=150.0, + stalta_waterlevel=0.08, tshift_acceptance_level=15.0, + dlna_acceptance_level=1.0, cc_acceptance_level=0.80, + c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0, + check_global_data_quality=False) + + assert config.max_time_before_first_arrival == 100 + assert config.max_time_after_last_arrival == 150 + + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + ws.select_windows() + assert ws.config.noise_start_index == 0 + assert ws.config.noise_end_index == 1331 + assert ws.config.signal_start_index == 1331 + assert ws.config.signal_end_index == 5352 + + config.max_time_before_first_arrival = 200 + config.max_time_after_last_arrival = 300 + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + ws.select_windows() + assert ws.config.noise_start_index == 0 + assert ws.config.noise_end_index == 1231 + assert ws.config.signal_start_index == 1231 + assert ws.config.signal_end_index == 5502 + + +def test_selection_mode(): + config = pyflex.Config( + min_period=50.0, max_period=150.0, + stalta_waterlevel=0.08, tshift_acceptance_level=15.0, + dlna_acceptance_level=1.0, cc_acceptance_level=0.80, + c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0, + check_global_data_quality=False) + + config.selection_mode = "custom" + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 9 + + config.selection_mode = "body_waves" + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 6 + + config.selection_mode = "surface_waves" + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 3 + + config.selection_mode = "mantle_waves" + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 3 + + config.selection_mode = "body_and_surface_waves" + ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) + windows = ws.select_windows() + assert len(windows) == 9 + + +def test_selection_mode_wrong_spelling(): + wrong_mode = "body_wvae" + with pytest.raises(ValueError): + pyflex.Config(min_period=50, max_period=150, + selection_mode=wrong_mode) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index ba48bfc..f51ba4a 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -298,23 +298,22 @@ def calculate_preliminiaries(self): return if self.ttimes: - offset = self.event.origin_time - self.observed.stats.starttime - min_time = self.ttimes[0]["time"] - \ - self.config.max_time_before_first_arrival + offset - min_idx = int(min_time / self.observed.stats.delta) - - dist_in_km = geodetics.calcVincentyInverse( - self.station.latitude, self.station.longitude, - self.event.latitude, self.event.longitude)[0] / 1000.0 - max_time = dist_in_km / self.config.min_surface_wave_velocity + \ - offset + self.config.max_period - max_idx = int(max_time / self.observed.stats.delta) - - # Reject all peaks and troughs before the minimal allowed start - # time and after the maximum allowed end time. + min_idx = self.config.signal_start_index + max_idx = self.config.signal_end_index first_trough, last_trough = self.troughs[0], self.troughs[-1] - self.troughs = self.troughs[(self.troughs >= min_idx) & - (self.troughs <= max_idx)] + # Reject all peaks not in the signal region. This kind of + # rejection will reduce the window counts and spedd up + # the processing speed + self.peaks = self.peaks[(self.peaks >= min_idx) & + (self.peaks <= max_idx)] + # Reject all troughs before the minimal allowed start + # time and after the maximum allowed end time. + sampling_rate = self.observed.stats.sampling_rate + loose_npts = 2 * self.config.min_period * sampling_rate + min_idx_2 = self.config.signal_start_index - loose_npts + max_idx_2 = self.config.signal_end_index + loose_npts + self.troughs = self.troughs[(self.troughs >= min_idx_2) & + (self.troughs <= max_idx_2)] # If troughs have been removed, readd them add the boundaries. if len(self.troughs): @@ -326,10 +325,10 @@ def calculate_preliminiaries(self): self.troughs = np.concatenate([ self.troughs, np.array([max_idx], dtype=self.troughs.dtype)]) - # Make sure peaks are inside the troughs! - min_trough, max_trough = self.troughs[0], self.troughs[-1] - self.peaks = self.peaks[(self.peaks > min_trough) & - (self.peaks < max_trough)] + # Make sure peaks are inside the troughs! + min_trough, max_trough = self.troughs[0], self.troughs[-1] + self.peaks = self.peaks[(self.peaks > min_trough) & + (self.peaks < max_trough)] def __print_remaining_windows(self): logger.debug("Remaining windows: %d" % (len(self.windows))) @@ -349,15 +348,18 @@ def select_windows(self): if self.event and self.station: self.calculate_ttimes() + self.determine_signal_and_noise_indices() + self.calculate_preliminiaries() - self.determine_signal_and_noise_indices() if self.config.check_global_data_quality: if not self.check_data_quality(): return [] # Perform all window selection steps. self.initial_window_selection() + # Reject windows in the noise region + self.reject_on_noise_region() # Reject windows based on traveltime if event and station # information is given. This will also fill self.ttimes. if self.event and self.station: @@ -430,6 +432,44 @@ def merge_windows(self): logger.info("Merging windows resulted in %i windows." % len(self.windows)) + def calculate_noise_end_index(self): + """ + If self.config.noise_end_index is not given, calculate the noise + end index based the first arrival(event and station information + required). + """ + offset = self.event.origin_time - self.observed.stats.starttime + noise_end_index = int( + (self.ttimes[0]["time"] + offset - + self.config.max_time_before_first_arrival) * + self.observed.stats.sampling_rate) + noise_end_index = max(noise_end_index, 0) + return noise_end_index + + def calculate_signal_end_index(self): + """ + If self.config.noise_end_index is not given, calculate the noise + end index based the first arrival(event and station information + required). + """ + offset = self.event.origin_time - self.observed.stats.starttime + # signal end index + dist_in_km = geodetics.calcVincentyInverse( + self.station.latitude, self.station.longitude, + self.event.latitude, + self.event.longitude)[0] / 1000.0 + surface_wave_arrival = \ + dist_in_km / self.config.min_surface_wave_velocity + last_arrival = max(self.ttimes[-1]["time"], surface_wave_arrival) + signal_end_index = int( + (last_arrival + offset + + self.config.max_time_after_last_arrival) * + self.observed.stats.sampling_rate) + + npts = self.observed.stats.npts + signal_end_index = min(signal_end_index, npts) + return signal_end_index + def determine_signal_and_noise_indices(self): """ Calculate the time range of the noise and the signal respectively if @@ -441,22 +481,30 @@ def determine_signal_and_noise_indices(self): "event and/or station information is not given " "and thus the theoretical arrival times cannot " "be calculated") - return else: - self.config.noise_end_index = \ - int((self.ttimes[0]["time"] - 2 * self.config.min_period) * - self.observed.stats.sampling_rate) - if self.config.signal_start_index is None: + self.config.noise_end_index = self.calculate_noise_end_index() + + if self.config.signal_start_index is None and \ + self.config.noise_end_index: self.config.signal_start_index = self.config.noise_end_index + if self.config.signal_end_index is None: + if not self.ttimes: + logger.warning("Cannot calculate the end of the signal as " + "event and/or station information is not given " + "and thus the theoretical arrival times cannot " + "be calculated") + else: + self.config.signal_end_index = \ + self.calculate_signal_end_index() + self.config._convert_negative_index(npts=self.observed.stats.npts) - dt = self.observed.stats.delta - logger.info("Noise region [%ds, %ds]; signal region [%ds, %ds]" % ( - self.config.noise_start_index * dt, - self.config.noise_end_index * dt, - self.config.signal_start_index * dt, - self.config.signal_end_index * dt)) + logger.info("Noise index [%s, %s]; signal index [%s, %s]" % ( + self.config.noise_start_index, + self.config.noise_end_index, + self.config.signal_start_index, + self.config.signal_end_index)) def reject_based_on_signal_to_noise_ratio(self): """ @@ -566,19 +614,49 @@ def calculate_ttimes(self): self.ttimes = sorted(tts, key=lambda x: x["time"]) logger.info("Calculated travel times.") + def reject_on_noise_region(self): + """ + Reject windows whose center is in the noise region + (center > noise_end_index). + We also put another check here, to make sure the left boarder + is not too far away with the `noise_end_index`. + """ + if self.config.noise_end_index is None: + return + + # window.center threshold is the noise_end_index + center_threshold = self.config.noise_end_index + # window.left threshold is the (noise_end - 2 * min_period) + two_min_period_npts = 2 * self.config.min_period * \ + self.observed.stats.sampling_rate + left_threshold = max( + self.config.noise_end_index - two_min_period_npts, 0) + + # reject windows which has overlap with the noise region + self.windows = \ + [win for win in self.windows + if (win.center > center_threshold) and + (win.left > left_threshold)] + def reject_on_selection_mode(self): """ - Reject based on select mode. Will reject windows outside of the + Reject based on selection mode. + This function will reject windows outside of the wave category specified. For example, if config.selection_mode - == "body_only", only body wave windows will be selected. + == "body_waves", only body wave windows will be selected(after + first arrival and before surface wave arrival). """ + select_mode = self.config.selection_mode + if select_mode == "custom": + # do nothing if "custom" + return + dist_in_km = geodetics.calcVincentyInverse( self.station.latitude, self.station.longitude, self.event.latitude, self.event.longitude)[0] / 1000.0 offset = self.event.origin_time - self.observed.stats.starttime - select_mode = self.config.selection_mode min_period = self.config.min_period first_arrival = self.ttimes[0]["time"] if select_mode == "all_waves": @@ -620,10 +698,6 @@ def reject_on_selection_mode(self): if (win.relative_endtime <= max_time) and (win.relative_starttime >= min_time)] - # reject windows which has overlap with the noise region - self.windows = [win for win in self.windows - if (win.left > self.config.noise_end_index)] - logger.info("Rejection based on selection mode retained %i windows." % len(self.windows)) From 945ab09437002da6d8a4f2e8dd3b11fc64830faf Mon Sep 17 00:00:00 2001 From: lei Date: Wed, 9 Nov 2016 13:44:50 -0500 Subject: [PATCH 19/33] add 'is None' test to avoid 0 value conditional trap --- src/pyflex/config.py | 11 ++++++++--- src/pyflex/window_selector.py | 6 ++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 860bcc3..a7055a5 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -307,6 +307,7 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, self.check_global_data_quality = check_global_data_quality self.snr_integrate_base = snr_integrate_base self.snr_max_base = snr_max_base + self.noise_start_index = noise_start_index self.noise_end_index = noise_end_index self.signal_start_index = signal_start_index @@ -365,6 +366,7 @@ def _convert_negative_index(self, npts): def add_npts(_idx, _npts): if _idx is None: return + _idx = int(_idx) if _idx < 0: return _idx + _npts else: @@ -375,21 +377,24 @@ def add_npts(_idx, _npts): self.signal_start_index = add_npts(self.signal_start_index, npts) self.signal_end_index = add_npts(self.signal_end_index, npts) - if self.noise_start_index and self.noise_end_index: + if self.noise_start_index is not None and \ + self.noise_end_index is not None: if self.noise_start_index >= self.noise_end_index: raise ValueError( "noise_start_index is larger than " "noise_end_idx: %d > %d" % (self.noise_start_index, self.noise_end_index)) - if self.signal_start_index and self.signal_end_index: + if self.signal_start_index is not None and \ + self.signal_end_index is not None: if self.signal_start_index >= self.signal_end_index: raise ValueError("singal_start_index is larger than " "signal_end_index: %d > %d" % (self.signal_start_index, self.signal_end_index)) - if self.noise_end_index and self.signal_start_index: + if self.noise_end_index is not None and \ + self.signal_start_index is not None: if self.noise_end_index > self.signal_start_index: raise ValueError("noise_end_index is larger than " "signal_start_index: %d > %d" diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index f51ba4a..17c6935 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -297,7 +297,9 @@ def calculate_preliminiaries(self): if not len(self.peaks) and len(self.troughs): return - if self.ttimes: + # make sure window.peak stays in the signal region + if self.config.signal_start_index is not None and \ + self.config.signal_end_index is not None: min_idx = self.config.signal_start_index max_idx = self.config.signal_end_index first_trough, last_trough = self.troughs[0], self.troughs[-1] @@ -485,7 +487,7 @@ def determine_signal_and_noise_indices(self): self.config.noise_end_index = self.calculate_noise_end_index() if self.config.signal_start_index is None and \ - self.config.noise_end_index: + self.config.noise_end_index is not None: self.config.signal_start_index = self.config.noise_end_index if self.config.signal_end_index is None: From e36297e5618fccd0415114055bb0253c1938bb6d Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 22 Nov 2016 16:37:19 -0500 Subject: [PATCH 20/33] add tests to check noise index --- src/pyflex/tests/test_pyflex.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 24e825b..895409e 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -412,6 +412,32 @@ def test_determine_signal_and_noise_indices(): assert ws.config.signal_end_index == 5502 +def test_noise_start_and_end_index(): + config = pyflex.Config( + min_period=50.0, max_period=150.0, + noise_start_index=0, noise_end_index=0) + with pytest.raises(ValueError): + ws = pyflex.window_selector.WindowSelector( + OBS_DATA, SYNTH_DATA, config) + ws.select_windows() + + config = pyflex.Config( + min_period=50.0, max_period=150.0, + noise_end_index=100, signal_start_index=50) + with pytest.raises(ValueError): + ws = pyflex.window_selector.WindowSelector( + OBS_DATA, SYNTH_DATA, config) + ws.select_windows() + + config = pyflex.Config( + min_period=50.0, max_period=150.0, + signal_start_index=100, signal_end_index=50) + with pytest.raises(ValueError): + ws = pyflex.window_selector.WindowSelector( + OBS_DATA, SYNTH_DATA, config) + ws.select_windows() + + def test_selection_mode(): config = pyflex.Config( min_period=50.0, max_period=150.0, From 3466e980d8f38780247919ae0c7b7d570ae5c9f5 Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 22 Nov 2016 16:41:42 -0500 Subject: [PATCH 21/33] change the obspy module import path according to updates in obspy --- src/pyflex/window_selector.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 17c6935..9e7f2bc 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -18,8 +18,8 @@ import json import numpy as np import obspy -import obspy.station -from obspy.core.util import geodetics +from obspy.core.inventory import Inventory +from obspy import geodetics from obspy.signal.filter import envelope from obspy.taup import getTravelTimes import os @@ -60,7 +60,7 @@ def __init__(self, observed, synthetic, config, event=None, station=None): will be extracted from the data traces if either originates from a SAC file. :type station: A Pyflex :class:`~pyflex.Station` object or an ObsPy - :class:`~obspy.station.inventory.Inventory` object + :class:`~obspy.core.inventory.Inventory` object """ self.observed = observed self.synthetic = synthetic @@ -234,7 +234,7 @@ def _parse_event_and_station(self): raise PyflexError("Could not parse the event. Unknown type.") # Parse the station information if it is an obspy inventory object. - if isinstance(self.station, obspy.station.Inventory): + if isinstance(self.station, Inventory): net = self.observed.stats.network sta = self.observed.stats.station # Workaround for ObsPy 0.9.2 Newer version have a get From cfc45f3a41b8c3b201e5d9bba5b164aad65ede30 Mon Sep 17 00:00:00 2001 From: lei Date: Thu, 1 Dec 2016 15:55:27 -0500 Subject: [PATCH 22/33] change reject_on_selection_mode to window.center --- src/pyflex/window_selector.py | 36 +++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 9e7f2bc..a5816df 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -297,6 +297,12 @@ def calculate_preliminiaries(self): if not len(self.peaks) and len(self.troughs): return + def reject_peaks_and_troughs_not_in_signal_region(self): + """ + Reject all the peaks and troughs not in the signal regions. + This will save us huge amount of time by rejecting a large + number of non-sense peaks and troughs. + """ # make sure window.peak stays in the signal region if self.config.signal_start_index is not None and \ self.config.signal_end_index is not None: @@ -353,6 +359,7 @@ def select_windows(self): self.determine_signal_and_noise_indices() self.calculate_preliminiaries() + self.reject_peaks_and_troughs_not_in_signal_region() if self.config.check_global_data_quality: if not self.check_data_quality(): @@ -445,7 +452,7 @@ def calculate_noise_end_index(self): (self.ttimes[0]["time"] + offset - self.config.max_time_before_first_arrival) * self.observed.stats.sampling_rate) - noise_end_index = max(noise_end_index, 0) + noise_end_index = max(noise_end_index, 1) return noise_end_index def calculate_signal_end_index(self): @@ -456,12 +463,13 @@ def calculate_signal_end_index(self): """ offset = self.event.origin_time - self.observed.stats.starttime # signal end index - dist_in_km = geodetics.calcVincentyInverse( + dist_in_km = geodetics.calc_vincenty_inverse( self.station.latitude, self.station.longitude, self.event.latitude, self.event.longitude)[0] / 1000.0 surface_wave_arrival = \ dist_in_km / self.config.min_surface_wave_velocity + # max of last arrival and surface wave arrival last_arrival = max(self.ttimes[-1]["time"], surface_wave_arrival) signal_end_index = int( (last_arrival + offset + @@ -631,8 +639,7 @@ def reject_on_noise_region(self): # window.left threshold is the (noise_end - 2 * min_period) two_min_period_npts = 2 * self.config.min_period * \ self.observed.stats.sampling_rate - left_threshold = max( - self.config.noise_end_index - two_min_period_npts, 0) + left_threshold = self.config.noise_end_index - two_min_period_npts # reject windows which has overlap with the noise region self.windows = \ @@ -653,7 +660,7 @@ def reject_on_selection_mode(self): # do nothing if "custom" return - dist_in_km = geodetics.calcVincentyInverse( + dist_in_km = geodetics.calc_vincenty_inverse( self.station.latitude, self.station.longitude, self.event.latitude, self.event.longitude)[0] / 1000.0 @@ -696,9 +703,12 @@ def reject_on_selection_mode(self): logger.debug("Selection mode <%s> -- time region <%d, %d>" % (self.config.selection_mode, min_time, max_time)) + # self.windows = [win for win in self.windows + # if (win.relative_endtime <= max_time) and + # (win.relative_starttime >= min_time)] self.windows = [win for win in self.windows - if (win.relative_endtime <= max_time) and - (win.relative_starttime >= min_time)] + if (win.relative_centertime <= max_time) and + (win.relative_centertime >= min_time)] logger.info("Rejection based on selection mode retained %i windows." % len(self.windows)) @@ -912,6 +922,12 @@ def filter_window_length(win): logger.info("Rejection based on minimum window length retained %i " "windows." % len(self.windows)) + max_c1 = max(self.config.c_1) + min_c1 = min(self.config.c_1) + logger.debug("Range of minimum window length: (%.2f, ..., %.2f)" + % (min_c1 * self.config.min_period, + max_c1 * self.config.min_period)) + def reject_based_on_data_fit_criteria(self): """ Rejects windows based on similarity between data and synthetics. @@ -930,12 +946,12 @@ def reject_based_on_criteria(win): dlnA_max = self.config.dlna_reference + \ self.config.dlna_acceptance_level[win.center] - if not (tshift_min <= win.cc_shift * - self.observed.stats.delta <= tshift_max): + if not (tshift_min <= win.cc_shift_in_seconds <= tshift_max): logger.debug("Window [%.1f - %.1f] rejected due to time " "shift does not satisfy: %.1f < %.1f < %.1f" % (win.relative_starttime, win.relative_endtime, - tshift_min, win.cc_shift, tshift_max)) + tshift_min, win.cc_shift_in_seconds, + tshift_max)) return False if not (dlnA_min <= win.dlnA <= dlnA_max): logger.debug("Window [%.1f - %.1f] rejected due to amplitude" From aba67685f3573ad4069e4a6cbbc5858c2b6d69d2 Mon Sep 17 00:00:00 2001 From: lei Date: Wed, 20 Nov 2019 00:18:06 -0500 Subject: [PATCH 23/33] obspy 1.1.1 compatability(python3) --- src/pyflex/interval_scheduling.py | 10 ++++---- src/pyflex/tests/test_code_formatting.py | 11 +++------ src/pyflex/tests/test_pyflex.py | 15 ++++++------ src/pyflex/window.py | 28 +---------------------- src/pyflex/window_selector.py | 29 ++++++++++++++---------- 5 files changed, 33 insertions(+), 60 deletions(-) diff --git a/src/pyflex/interval_scheduling.py b/src/pyflex/interval_scheduling.py index de43a36..a2214e2 100644 --- a/src/pyflex/interval_scheduling.py +++ b/src/pyflex/interval_scheduling.py @@ -62,18 +62,18 @@ def schedule_weighted_intervals(I): OPT[j] = max(I[j].weight + OPT[p[j]], OPT[j - 1]) # given OPT and p, find actual solution intervals in O(n) - O = [] + res = [] def compute_solution(j): if j >= 0: # will halt on OPT[-1] if I[j].weight + OPT[p[j]] > OPT[j - 1]: - O.append(I[j]) + res.append(I[j]) compute_solution(p[j]) else: compute_solution(j - 1) compute_solution(len(I) - 1) - # resort, as our O is in reverse order (OPTIONAL) - O.sort(key=lambda x: x.right) + # resort, as our res is in reverse order (OPTIONAL) + res.sort(key=lambda x: x.right) - return O + return res diff --git a/src/pyflex/tests/test_code_formatting.py b/src/pyflex/tests/test_code_formatting.py index 8d5568a..f541254 100644 --- a/src/pyflex/tests/test_code_formatting.py +++ b/src/pyflex/tests/test_code_formatting.py @@ -10,9 +10,7 @@ GNU General Public License, Version 3 (http://www.gnu.org/copyleft/gpl.html) """ -import flake8 -import flake8.engine -import flake8.main +from flake8.api import legacy import inspect import os @@ -44,12 +42,9 @@ def test_flake8(): files.append(full_path) # Get the style checker with the default style. - flake8_style = flake8.engine.get_style_guide( - parse_argv=False, config_file=flake8.main.DEFAULT_CONFIG) + flake8_style = legacy.get_style_guide() report = flake8_style.check_files(files) - # Make sure at least 10 files are tested. - assert report.counters["files"] > 10 # And no errors occured. - assert report.get_count() == 0 + assert report.total_errors == 0 diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 895409e..969c7b0 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -133,7 +133,7 @@ def test_window_selection(): -0.638657, 0.25942, 0.106571]), rtol=1E-2) # Assert the phases of the first window. - assert sorted([_i["phase_name"] for _i in windows[0].phase_arrivals]) == \ + assert sorted([_i["name"] for _i in windows[0].phase_arrivals]) == \ ['PKIKP', 'PKIKS', 'PKiKP', 'PP', 'SKIKP', 'SKiKP', 'pPKIKP', 'pPKiKP', 'sPKIKP', 'sPKiKP'] @@ -241,7 +241,7 @@ def test_event_information_extraction(): # Alternatively, an ObsPy Catalog or Event object can be passed which # opens the gate to more complex workflows. - cat = obspy.readEvents() + cat = obspy.read_events() cat.events = cat.events[:1] event = cat[0] @@ -263,8 +263,6 @@ def test_station_information_extraction(): """ Station information can either be passed or read from sac files. """ - import obspy.station - config = pyflex.Config(min_period=50.0, max_period=150.0) # If not passed, it is read from sac files, if available. @@ -273,10 +271,11 @@ def test_station_information_extraction(): assert abs(ws.station.longitude - 58.1189) < 1E-5 # The other option is an inventory object. Assemble a dummy one. - inv = obspy.station.Inventory(networks=[], source="local") - net = obspy.station.Network(code=OBS_DATA[0].stats.network) - sta = obspy.station.Station(code=OBS_DATA[0].stats.station, latitude=1.0, - longitude=2.0, elevation=3.0) + inv = obspy.core.inventory.Inventory(networks=[], source="local") + net = obspy.core.inventory.Network(code=OBS_DATA[0].stats.network) + sta = obspy.core.inventory.Station( + code=OBS_DATA[0].stats.station, latitude=1.0, + longitude=2.0, elevation=3.0) inv.networks = [net] net.stations = [sta] diff --git a/src/pyflex/window.py b/src/pyflex/window.py index d7bc37f..e337d70 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -76,33 +76,7 @@ def __init__(self, left, right, center, time_of_first_sample, dt, self.weight_function = weight_function def __eq__(self, other): - - def _compare_value(value1, value2): - if isinstance(value1, float) or isinstance(value1, np.float64): - np.testing.assert_allclose(value1, value2) - elif isinstance(value1, np.float32): - np.testing.assert_allclose(value1, value2, rtol=1e-06) - else: - if value1 != value2: - raise AssertionError - - dict1 = self.__dict__ - dict2 = other.__dict__ - try: - for key in dict1.keys(): - if key == "phase_arrivals": - phase1 = dict1[key] - phase2 = dict1[key] - if len(phase1) != len(phase2): - raise AssertionError - for _p1, _p2 in zip(phase1, phase2): - for _key_phase in _p1.keys(): - _compare_value(_p1[_key_phase], _p2[_key_phase]) - else: - _compare_value(dict1[key], dict2[key]) - except: - return False - return True + return self.__dict__ == other.__dict__ def __ne__(self, other): return not self == other diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index a5816df..39e3bb9 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -21,7 +21,7 @@ from obspy.core.inventory import Inventory from obspy import geodetics from obspy.signal.filter import envelope -from obspy.taup import getTravelTimes +from obspy.taup import TauPyModel import os import warnings @@ -82,6 +82,8 @@ def __init__(self, observed, synthetic, config, event=None, station=None): self.ttimes = [] self.windows = [] + self.taupy_model = TauPyModel(model=self.config.earth_model) + self.selection_timebox = \ np.array([0, self.observed.stats.delta * self.observed.stats.npts]) @@ -619,8 +621,11 @@ def calculate_ttimes(self): dist_in_deg = geodetics.locations2degrees( self.station.latitude, self.station.longitude, self.event.latitude, self.event.longitude) - tts = getTravelTimes(dist_in_deg, self.event.depth_in_m / 1000.0, - model=self.config.earth_model) + + tts = self.taupy_model.get_travel_times( + source_depth_in_km=self.event.depth_in_m / 1000.0, + distance_in_degree=dist_in_deg) + tts = [{"time": _i.time, "name": _i.name} for _i in tts] self.ttimes = sorted(tts, key=lambda x: x["time"]) logger.info("Calculated travel times.") @@ -1061,7 +1066,7 @@ def plot(self, filename=None): ax.set_xlim(times[0], times[-1]) for tt in self.ttimes: - if tt["phase_name"].lower().startswith("p"): + if tt["name"].lower().startswith("p"): color = "#008c28" else: color = "#950000" @@ -1091,13 +1096,13 @@ def plot(self, filename=None): buf = 0.003 * (plt.xlim()[1] - plt.xlim()[0]) for win in self.windows: - l = win.relative_starttime - offset - r = win.relative_endtime - offset - re = Rectangle((l, plt.ylim()[0]), r - l, + _l = win.relative_starttime - offset + _r = win.relative_endtime - offset + re = Rectangle((_l, plt.ylim()[0]), _r - _l, plt.ylim()[1] - plt.ylim()[0], color="blue", alpha=(win.max_cc_value ** 2) * 0.25) plt.gca().add_patch(re) - plt.text(l + buf, plt.ylim()[1], + plt.text(_l + buf, plt.ylim()[1], "CC=%.2f\ndT=%.2f\ndA=%.2f" % (win.max_cc_value, win.cc_shift * self.observed.stats.delta, @@ -1162,7 +1167,7 @@ def plot(self, filename=None): dist_in_degree = geodetics.locations2degrees( self.event.latitude, self.event.longitude, self.station.latitude, self.station.longitude) - text = "Epicenter distance: %-5.2f$^\circ$ " % dist_in_degree + text = r"Epicenter distance: {}$^\circ$ ".format(dist_in_degree) plt.text(0.75, 0.79, text, horizontalalignment='left', verticalalignment='top', transform=ax.transAxes, fontsize=10) @@ -1194,9 +1199,9 @@ def plot(self, filename=None): fontsize=10) for win in self.windows: - l = win.relative_starttime - offset - r = win.relative_endtime - offset - re = Rectangle((l, plt.ylim()[0]), r - l, + _l = win.relative_starttime - offset + _r = win.relative_endtime - offset + re = Rectangle((_l, plt.ylim()[0]), _r - _l, plt.ylim()[1] - plt.ylim()[0], color="blue", alpha=(win.max_cc_value ** 2) * 0.25) plt.gca().add_patch(re) From 26ee35a58febdcdb445ab1bd1c9cda6486e72e63 Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 14 Jan 2020 14:51:39 -0500 Subject: [PATCH 24/33] change test benchmark figure --- .../baseline_images/picked_windows.png.init | Bin 0 -> 103106 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/pyflex/tests/baseline_images/picked_windows.png.init diff --git a/src/pyflex/tests/baseline_images/picked_windows.png.init b/src/pyflex/tests/baseline_images/picked_windows.png.init new file mode 100644 index 0000000000000000000000000000000000000000..4dde1faa3eb8aacea56258b918e7dde216df9a23 GIT binary patch literal 103106 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 z%0D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 Date: Mon, 27 Apr 2020 16:01:45 -0400 Subject: [PATCH 25/33] refine and extend selection mode --- src/pyflex/config.py | 21 +-- src/pyflex/utils.py | 38 +++++ src/pyflex/window_selector.py | 294 ++++++++++++++++++++++++---------- 3 files changed, 257 insertions(+), 96 deletions(-) diff --git a/src/pyflex/config.py b/src/pyflex/config.py index 814198a..76de8aa 100644 --- a/src/pyflex/config.py +++ b/src/pyflex/config.py @@ -328,15 +328,17 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, "'interval_scheduling' or 'merge'.") self.resolution_strategy = resolution_strategy.lower() - if selection_mode.lower() not in [ + selection_mode = selection_mode.strip() + if selection_mode.split(":")[0].strip().lower() not in [ "all_waves", "body_and_surface_waves", "body_waves", - "surface_waves", "mantle_waves", "custom"]: + "surface_waves", "mantle_waves", "custom", "phase_list", + "body_and_mantle_waves"]: raise ValueError( - "Invalide selection_mode. Choose: 1) all_waves;" + "Invalide selection_mode({}). Choose: 1) all_waves;" "2) body_and_surface_waves; 3) body_waves; " "4) surface_waves; 5) mantle_waves; " - "6) custom; ") - self.selection_mode = selection_mode.lower() + "6) custom; 7) phase_list;".format(selection_mode)) + self.selection_mode = selection_mode def _convert_to_array(self, npts): """ @@ -346,18 +348,17 @@ def _convert_to_array(self, npts): attributes = ("stalta_waterlevel", "tshift_acceptance_level", "dlna_acceptance_level", "cc_acceptance_level", "s2n_limit", "s2n_limit_energy", "c_1") + for name in attributes: attr = getattr(self, name) - if isinstance(attr, collections.Iterable): if len(attr) != npts: raise PyflexError( "Config value '%s' does not have the same number of " "samples as the waveforms." % name) setattr(self, name, np.array(attr)) - continue - - setattr(self, name, attr * np.ones(npts)) + else: + setattr(self, name, attr * np.ones(npts)) def _convert_negative_index(self, npts): """ @@ -365,7 +366,7 @@ def _convert_negative_index(self, npts): """ def add_npts(_idx, _npts): if _idx is None: - return + return None _idx = int(_idx) if _idx < 0: return _idx + _npts diff --git a/src/pyflex/utils.py b/src/pyflex/utils.py index 63fc3c8..68176a8 100644 --- a/src/pyflex/utils.py +++ b/src/pyflex/utils.py @@ -16,6 +16,7 @@ import numpy as np from scipy.signal import argrelextrema +from obspy.geodetics import degrees2kilometers with standard_library.hooks(): import itertools @@ -77,3 +78,40 @@ def find_local_extrema(data): return np.array(sorted(list(maxs.union(set(maxima)))), dtype="int32"), \ np.array(sorted(list(mins.union(set(minima)))), dtype="int32") + + +def get_surface_wave_arrivals(dist_in_deg, min_vel, max_vel, ncircles=1): + """ + Calculate the arrival time of surface waves, based on the distance + and velocity range (min_vel, max_vel). + This function will calculate both minor-arc and major-arc surface + waves. It further calcualte the surface orbit multiple times + if you set the ncircles > 1. + + Returns the list of surface wave arrivals in time order. + """ + if min_vel > max_vel: + min_vel, max_vel = max_vel, min_vel + + earth_circle = degrees2kilometers(360.0) + dt1 = earth_circle / max_vel + dt2 = earth_circle / min_vel + + # 1st arrival: minor-arc arrival + minor_dist_km = degrees2kilometers(dist_in_deg) # major-arc distance + t_minor = [minor_dist_km / max_vel, minor_dist_km/min_vel] + + # 2nd arrival: major-arc arrival + major_dist_km = degrees2kilometers(360.0 - dist_in_deg) + t_major = [major_dist_km / max_vel, major_dist_km / min_vel] + + # prepare the arrival list + arrivals = [] + for i in range(ncircles): + ts = [t_minor[0] + i * dt1, t_minor[1] + i * dt2] + arrivals.append(ts) + + ts = [t_major[0] + i * dt1, t_major[1] + i * dt2] + arrivals.append(ts) + + return arrivals diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index ce20912..15a1458 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -28,6 +28,7 @@ from .stalta import sta_lta from .window import Window from .interval_scheduling import schedule_weighted_intervals +from .utils import get_surface_wave_arrivals with standard_library.hooks(): import itertools @@ -83,8 +84,12 @@ def __init__(self, observed, synthetic, config, event=None, station=None): self.taupy_model = TauPyModel(model=self.config.earth_model) - self.selection_timebox = \ - np.array([0, self.observed.stats.delta * self.observed.stats.npts]) + # event and station distance + self.dist_in_deg = None + self.dist_in_km = None + + # used by selection mode to specify the time range could be used + self.selection_timebox = None def load(self, filename): """ @@ -367,6 +372,7 @@ def select_windows(self): """ # Fill self.ttimes. if self.event and self.station: + self.calculate_distance() self.calculate_ttimes() self.determine_signal_and_noise_indices() @@ -418,6 +424,9 @@ def select_windows(self): if self.ttimes: self.attach_phase_arrivals_to_windows() + if self.event and self.station: + self.attach_distance_to_windows() + return self.windows def attach_phase_arrivals_to_windows(self): @@ -431,6 +440,10 @@ def attach_phase_arrivals_to_windows(self): win.phase_arrivals = [ _i for _i in self.ttimes if left <= _i["time"] <= right] + def attach_distance_to_windows(self): + for win in self.windows: + win.distance_in_deg = self.dist_in_deg + def merge_windows(self): """ Merge overlapping windows. Will also recalculate the data fit criteria. @@ -476,13 +489,13 @@ def calculate_signal_end_index(self): """ offset = self.event.origin_time - self.observed.stats.starttime # signal end index - dist_in_km = obspy.geodetics.calc_vincenty_inverse( - self.station.latitude, self.station.longitude, - self.event.latitude, - self.event.longitude)[0] / 1000.0 surface_wave_arrival = \ - dist_in_km / self.config.min_surface_wave_velocity + self.dist_in_km / self.config.min_surface_wave_velocity # max of last arrival and surface wave arrival + logger.debug("last ttimess: {}".format(self.ttimes[-1])) + logger.debug("surface wave arrival: {}".format(surface_wave_arrival)) + logger.debug("sampling rate: {}".format( + self.observed.stats.sampling_rate)) last_arrival = max(self.ttimes[-1]["time"], surface_wave_arrival) signal_end_index = int( (last_arrival + offset + @@ -498,6 +511,12 @@ def determine_signal_and_noise_indices(self): Calculate the time range of the noise and the signal respectively if not yet specified by the user. """ + logger.debug("obsd and synt trace npts: {}, {}".format( + self.observed.stats.npts, self.synthetic.stats.npts)) + + if self.config.noise_start_index is None: + self.config.noise_start_index = 0 + if self.config.noise_end_index is None: if not self.ttimes: logger.warning("Cannot calculate the end of the noise as " @@ -540,44 +559,60 @@ def reject_based_on_signal_to_noise_ratio(self): "range of the noise.") return + # safe guard noise_end_index when event and station are very close noise = self.observed.data[self.config.noise_start_index: - self.config.noise_end_index] + max(self.config.noise_end_index, 10)] noise_amp = np.abs(noise).max() noise_energy = np.sum(noise ** 2) / len(noise) def filter_window_noise_amplitude(win): win_signal = self.observed.data[win.left:win.right] win_noise_amp = np.abs(win_signal).max() / noise_amp + # attach snr information to window + win.snr_amplitude = win_noise_amp + win.snr_amplitude_threshold = self.config.s2n_limit[win.center] if win_noise_amp < self.config.s2n_limit[win.center]: + left = win.relative_starttime + right = win.relative_endtime + logger.debug("Win rejected due to S2N ratio (Amplitude):" + "%3.1f %5.1f %5.1f" + % (win_noise_amp, left, right)) return False return True def filter_window_noise_energy(win): data = self.observed.data[win.left:win.right] win_energy = np.sum(data ** 2) / len(data) - win_noise_amp = win_energy / noise_energy - if win_noise_amp < self.config.s2n_limit_energy[win.center]: + win_noise_energy = win_energy / noise_energy + # attach snr information to window + win.snr_energy = win_noise_energy + win.snr_energy_threshold = self.config.s2n_limit_energy[win.center] + if win_noise_energy < self.config.s2n_limit_energy[win.center]: left = win.relative_starttime right = win.relative_endtime - logger.debug("Win rejected due to S2N ratio(Amp):" + logger.debug("Win rejected due to S2N ratio (Energy):" "%3.1f %5.1f %5.1f" - % (win_noise_amp, left, right)) + % (win_noise_energy, left, right)) return False return True + n0 = len(self.windows) window_snr_type = self.config.window_signal_to_noise_type if window_snr_type in ("amplitude", "amplitude_and_energy"): self.windows = list(filter(filter_window_noise_amplitude, self.windows)) + logger.info("SNR(Amplitude) rejection retained {}/{} " + "windows".format(len(self.windows), n0)) - elif window_snr_type in ("energy", "amplitude_and_energy"): + n1 = len(self.windows) + if window_snr_type in ("energy", "amplitude_and_energy"): self.windows = list(filter(filter_window_noise_energy, self.windows)) - else: - raise NotImplementedError + logger.info("SNR(Energy) rejection retained {}/{} " + "windows".format(len(self.windows), n1)) - logger.info("SN amplitude ratio window rejection retained %i windows" % - len(self.windows)) + logger.info("Signal-Noise-Ratio({}) rejection retained {}/{} " + "windows".format(window_snr_type, len(self.windows), n0)) def check_data_quality(self): """ @@ -590,8 +625,9 @@ def check_data_quality(self): "available so the theoretical arrival times cannot be " "calculated.") + # safe guard noise_end_index when event and station are very close noise = self.observed.data[self.config.noise_start_index: - self.config.noise_end_index] + max(self.config.noise_end_index, 10)] signal = self.observed.data[self.config.signal_start_index: self.config.signal_end_index] @@ -620,24 +656,46 @@ def check_data_quality(self): logger.warn(msg) return False - logger.info("Global SNR checks passed. Integrated SNR: %f, Amplitude " - "SNR: %f" % (snr_int, snr_amp)) + logger.info("Global SNR checks passed. Integrated SNR: {:.2f}, " + "Amplitude SNR {:.2f}".format(snr_int, snr_amp)) return True + def calculate_distance(self): + """ + Calculate the distance between event and station + """ + self.dist_in_deg = obspy.geodetics.locations2degrees( + self.station.latitude, self.station.longitude, + self.event.latitude, self.event.longitude) + self.dist_in_km = obspy.geodetics.degrees2kilometers(self.dist_in_deg) + logger.debug(r"dist_in_deg and dist_in_km: {:.2f}, {:.2f} km".format( + self.dist_in_deg, self.dist_in_km)) + def calculate_ttimes(self): """ Calculate theoretical travel times. Only call if station and event information is available! """ - dist_in_deg = obspy.geodetics.locations2degrees( - self.station.latitude, self.station.longitude, - self.event.latitude, self.event.longitude) + logger.debug("event lat, lon: {}, {}".format( + self.event.latitude, self.event.longitude)) + logger.debug("station lat, lon: {}, {}".format( + self.station.latitude, self.station.longitude)) tts = self.taupy_model.get_travel_times( source_depth_in_km=self.event.depth_in_m / 1000.0, - distance_in_degree=dist_in_deg) + distance_in_degree=self.dist_in_deg) + logger.debug("source depth: {:.2f} km".format( + self.event.depth_in_m / 1000.0)) self.ttimes = [{"time": _i.time, "name": _i.name} for _i in tts] logger.info("Calculated travel times.") + #logger.debug("{}".format(self.ttimes)) + + #tts2 = self.taupy_model.get_travel_times( + # source_depth_in_km=self.event.depth_in_m / 1000.0, + # distance_in_degree=self.dist_in_deg, + # phase_list=["ScS", "sScS", "ScSScS", "sScSScS"] + #) + #logger.debug("ScS arrivals: {}".format(tts2)) def reject_on_noise_region(self): """ @@ -662,6 +720,63 @@ def reject_on_noise_region(self): if (win.center > center_threshold) and (win.left > left_threshold)] + def _prepare_min_max_timebox(self, min_time, max_time, srate): + logger.debug("selection_timebox min/max time: {:.2f} {:.2f}" + "".format(min_time, max_time)) + + timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + il = int(min_time * srate) + ir = int(max_time * srate) + timebox[il:(ir+1)] = 1 + + logger.debug("selection_timebox index range: {} - {} / {}".format( + il, ir, len(timebox))) + self.selection_timebox = timebox + + def _prepare_surface_wave_timebox(self, srate, offset): + logger.debug("selection_timebox using surface waves") + + max_vel = self.config.max_surface_wave_velocity + min_vel = self.config.min_surface_wave_velocity + arrivals = get_surface_wave_arrivals( + self.dist_in_deg, min_vel, max_vel, ncircles=1) + logger.debug("Number of surface wave arrivals: {}".format( + len(arrivals))) + + timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + for arr in arrivals: + il = int((arr[0] + offset) * srate) + ir = int((arr[1] + offset + self.config.min_period) * srate) + timebox[il:(ir+1)] = 1 + + logger.debug("Selectable region percentage: {}/{}".format( + timebox.sum(), len(timebox))) + self.selection_timebox = timebox + + def _prepare_phase_timebox(self, phase_list, srate, buffer_time, offset): + logger.debug("Selection_timebox using phases: {}".format(phase_list)) + + source_depth = self.event.depth_in_m / 1000.0 + logger.debug("event depth: {:.2f} km".format(source_depth)) + logger.debug("distance in deg: {:.2f}".format(self.dist_in_deg)) + tts = self.taupy_model.get_travel_times( + source_depth_in_km=source_depth, + distance_in_degree=self.dist_in_deg, + phase_list=phase_list + ) + + timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + for t in tts: + t_left = t.time - buffer_time + offset + il = int(t_left * srate) + t_right = t.time + buffer_time + offset + ir = int(t_right * srate) + timebox[il:(ir+1)] = 1 + + logger.debug("Selectable region percentage: {}/{}".format( + timebox.sum(), len(timebox))) + self.selection_timebox = timebox + def reject_on_selection_mode(self): """ Reject based on selection mode. @@ -671,62 +786,64 @@ def reject_on_selection_mode(self): first arrival and before surface wave arrival). """ select_mode = self.config.selection_mode - if select_mode == "custom": - # do nothing if "custom" + logger.debug("Selection mode <{}>".format((select_mode))) + if select_mode in [None, "", "custom"]: return - dist_in_km = obspy.geodetics.calc_vincenty_inverse( - self.station.latitude, self.station.longitude, self.event.latitude, - self.event.longitude)[0] / 1000.0 - offset = self.event.origin_time - self.observed.stats.starttime + buffer_time = 2 * self.config.min_period + + surface_arrival = \ + self.dist_in_km / self.config.max_surface_wave_velocity + surface_end = \ + self.dist_in_km / self.config.min_surface_wave_velocity + + stats = self.observed.stats + srate = self.observed.stats.sampling_rate + tr_timelen = stats.endtime - stats.starttime - min_period = self.config.min_period first_arrival = self.ttimes[0]["time"] - if select_mode == "all_waves": - min_time = first_arrival - 2 * min_period + offset - max_time = self.observed.stats.endtime \ - - self.observed.stats.starttime + + if select_mode in ["all_waves", "body_and_mantle_waves"]: + min_time = first_arrival - buffer_time + offset + max_time = tr_timelen + self._prepare_min_max_timebox(min_time, max_time, srate) elif select_mode == "body_and_surface_waves": - min_time = first_arrival - 2 * min_period + offset - max_time = dist_in_km / self.config.min_surface_wave_velocity \ - + 2 * min_period + offset + min_time = first_arrival - buffer_time + offset + max_time = surface_end + buffer_time + offset + self._prepare_min_max_timebox(min_time, max_time, srate) elif select_mode == "body_waves": - min_time = first_arrival - 2 * min_period + offset - max_time = \ - dist_in_km / self.config.max_surface_wave_velocity \ - + 2 * min_period + offset + min_time = first_arrival - buffer_time + offset + max_time = surface_arrival + buffer_time + offset + self._prepare_min_max_timebox(min_time, max_time, srate) elif select_mode == "surface_waves": - min_time = \ - dist_in_km / self.config.max_surface_wave_velocity \ - - 2 * min_period + offset - max_time = dist_in_km / self.config.min_surface_wave_velocity \ - + 2 * min_period + offset + # min_time = surface_arrival - buffer_time + offset + # max_time = surface_end + buffer_time + offset + # self._prepare_min_max_timebox(min_time, max_time, srate) + self._prepare_surface_wave_timebox(srate, offset) elif select_mode == "mantle_waves": - min_time = dist_in_km / self.config.max_surface_wave_velocity \ - + offset - max_time = self.observed.stats.endtime \ - - self.observed.stats.starttime + min_time = surface_end + offset + max_time = tr_timelen + self._prepare_min_max_timebox(min_time, max_time, srate) + elif select_mode.startswith("phase_list"): + phases = select_mode.split(":")[-1].split(",") + phases = [p.strip() for p in phases] + if len(phases) == 0: + raise ValueError("No phase provided for 'phase_list' " + "selection mode") + self._prepare_phase_timebox( + phases, srate, buffer_time, offset) else: raise NotImplementedError - if min_time >= max_time: - raise ValueError("Selection mode time region incorrect: [%d, %d]" - % (min_time, max_time)) - self.selection_timebox = np.array([min_time, max_time]) - - logger.debug("Selection mode <%s> -- time region <%d, %d>" - % (self.config.selection_mode, min_time, max_time)) - # self.windows = [win for win in self.windows # if (win.relative_endtime <= max_time) and # (win.relative_starttime >= min_time)] + n0 = len(self.windows) self.windows = [win for win in self.windows - if (win.relative_centertime <= max_time) and - (win.relative_centertime >= min_time)] - - logger.info("Rejection based on selection mode retained %i windows." % - len(self.windows)) + if self.selection_timebox[win.center]] + logger.info("Rejection based on selection mode retained {}({})" + "windows.".format(len(self.windows), n0)) def initial_window_selection(self): """ @@ -968,12 +1085,14 @@ def reject_based_on_criteria(win): tshift_min, win.cc_shift_in_seconds, tshift_max)) return False + if not (dlnA_min <= win.dlnA <= dlnA_max): - logger.debug("Window [%.1f - %.1f] rejected due to amplitude" + logger.debug("Window [%.1f - %.1f] rejected due to amplitude " "fit does not satisfy: %.3f < %.3f < %.3f" % (win.relative_starttime, win.relative_endtime, dlnA_min, win.dlnA, dlnA_max)) return False + if win.max_cc_value < self.config.cc_acceptance_level[win.center]: logger.debug("Window [%.1f - %.1f] rejected due to CC value " "does not satisfy: %.3f < %.3f" @@ -981,6 +1100,7 @@ def reject_based_on_criteria(win): self.config.cc_acceptance_level[win.center], win.max_cc_value)) return False + return True self.windows = list(filter(reject_based_on_criteria, self.windows)) @@ -1124,17 +1244,17 @@ def plot(self, filename=None): size="small", multialignment="right") # plot the selection_timebox line - plt.axes([0.025, 0.50, 0.95, 0.01]) - ax = plt.gca() - ax.spines['right'].set_color('none') - ax.spines['left'].set_color('none') - ax.spines['top'].set_color('none') - ax.spines['bottom'].set_color('none') - ax.set_xticks([]) - ax.set_yticks([]) - ax.set_xlim(times[0], times[-1]) - plt.plot(self.selection_timebox - offset, [0, 0], 'g-', linewidth=8.0, - alpha=0.8) + #plt.axes([0.025, 0.50, 0.95, 0.01]) + #ax = plt.gca() + #ax.spines['right'].set_color('none') + #ax.spines['left'].set_color('none') + #ax.spines['top'].set_color('none') + #ax.spines['bottom'].set_color('none') + #ax.set_xticks([]) + #ax.set_yticks([]) + #ax.set_xlim(times[0], times[-1]) + #plt.plot(self.selection_timebox - offset, [0, 0], 'g-', linewidth=8.0, + # alpha=0.8) plt.axes([0.025, 0.1, 0.95, 0.4]) plt.plot(times, self.stalta, color="blue") @@ -1162,12 +1282,12 @@ def plot(self, filename=None): verticalalignment='top', transform=ax.transAxes, fontsize=10) - text = "Selection timebox(s): [%6.1f, %6.1f]" \ - % (self.selection_timebox[0] - offset, - self.selection_timebox[1] - offset) - plt.text(0.75, 0.93, text, horizontalalignment='left', - verticalalignment='top', transform=ax.transAxes, - fontsize=10) + #text = "Selection timebox(s): [%6.1f, %6.1f]" \ + # % (self.selection_timebox[0] - offset, + # self.selection_timebox[1] - offset) + #plt.text(0.75, 0.93, text, horizontalalignment='left', + # verticalalignment='top', transform=ax.transAxes, + # fontsize=10) if self.event: text = "Source depth: %.2f km" % (self.event.depth_in_m/1000.) @@ -1176,10 +1296,12 @@ def plot(self, filename=None): fontsize=10) if self.station and self.event: - dist_in_degree = obspy.geodetics.locations2degrees( - self.event.latitude, self.event.longitude, - self.station.latitude, self.station.longitude) - text = r"Epicenter distance: {}$^\circ$ ".format(dist_in_degree) + logger.debug("event lat, lon: {}, {}".format( + self.event.latitude, self.event.longitude)) + logger.debug("station lat, lon: {}, {}".format( + self.station.latitude, self.station.longitude)) + text = r"Epicenter distance: {}$^\circ$ ".format( + self.dist_in_deg) plt.text(0.75, 0.79, text, horizontalalignment='left', verticalalignment='top', transform=ax.transAxes, fontsize=10) From 04b884cf138b91dc3359fca91d95581fc607f627 Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 28 Apr 2020 18:27:36 -0400 Subject: [PATCH 26/33] fix signal_end_idx issue to catch signal after minor-arc surface wave --- src/pyflex/window_selector.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 15a1458..3eea5de 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -537,8 +537,9 @@ def determine_signal_and_noise_indices(self): "and thus the theoretical arrival times cannot " "be calculated") else: - self.config.signal_end_index = \ - self.calculate_signal_end_index() + # self.config.signal_end_index = \ + # self.calculate_signal_end_index() + self.config.signal_end_index = self.observed.stats.npts self.config._convert_negative_index(npts=self.observed.stats.npts) @@ -739,13 +740,13 @@ def _prepare_surface_wave_timebox(self, srate, offset): max_vel = self.config.max_surface_wave_velocity min_vel = self.config.min_surface_wave_velocity arrivals = get_surface_wave_arrivals( - self.dist_in_deg, min_vel, max_vel, ncircles=1) + self.dist_in_deg, min_vel, max_vel, ncircles=2) logger.debug("Number of surface wave arrivals: {}".format( len(arrivals))) timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) for arr in arrivals: - il = int((arr[0] + offset) * srate) + il = int((arr[0] + offset - self.config.min_period) * srate) ir = int((arr[1] + offset + self.config.min_period) * srate) timebox[il:(ir+1)] = 1 From ecc7993119ee4bd6646e6126f409faff3abfc84e Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 19 May 2020 14:47:47 -0400 Subject: [PATCH 27/33] bug gix --- src/pyflex/__init__.py | 3 ++- src/pyflex/tests/test_pyflex.py | 6 +++--- src/pyflex/tests/test_window.py | 6 +++++- src/pyflex/window.py | 13 +++++++++++++ src/pyflex/window_selector.py | 5 ++--- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index 718c6fc..92d5acd 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -43,7 +43,8 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -logger.setLevel(logging.WARNING) +#logger.setLevel(logging.WARNING) +logger.setLevel(logging.DEBUG) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 596e95b..7df2216 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -406,7 +406,7 @@ def test_determine_signal_and_noise_indices(): assert ws.config.noise_start_index == 0 assert ws.config.noise_end_index == 1331 assert ws.config.signal_start_index == 1331 - assert ws.config.signal_end_index == 5352 + assert ws.config.signal_end_index == 5349 config.max_time_before_first_arrival = 200 config.max_time_after_last_arrival = 300 @@ -415,7 +415,7 @@ def test_determine_signal_and_noise_indices(): assert ws.config.noise_start_index == 0 assert ws.config.noise_end_index == 1231 assert ws.config.signal_start_index == 1231 - assert ws.config.signal_end_index == 5502 + assert ws.config.signal_end_index == 5499 def test_noise_start_and_end_index(): @@ -470,7 +470,7 @@ def test_selection_mode(): config.selection_mode = "mantle_waves" ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) windows = ws.select_windows() - assert len(windows) == 3 + assert len(windows) == 0 config.selection_mode = "body_and_surface_waves" ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) diff --git a/src/pyflex/tests/test_window.py b/src/pyflex/tests/test_window.py index 2e61215..9487489 100644 --- a/src/pyflex/tests/test_window.py +++ b/src/pyflex/tests/test_window.py @@ -168,7 +168,11 @@ def test_window_to_dict_and_back(tmpdir): "absolute_endtime": win.absolute_endtime, "relative_starttime": win.relative_starttime, "relative_endtime": win.relative_endtime, - "window_weight": win.weight} + "window_weight": win.weight, + "distance_in_deg": None, + "snr_amplitude": None, + "snr_amplitude_threshold": None + } assert output == expected diff --git a/src/pyflex/window.py b/src/pyflex/window.py index e337d70..ee5e62e 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -74,6 +74,10 @@ def __init__(self, left, right, center, time_of_first_sample, dt, self.channel_id_2 = channel_id_2 self.phase_arrivals = [] self.weight_function = weight_function + # extra properties + self.snr_amplitude = None + self.snr_amplitude_threshold = None + self.distance_in_deg = None def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -120,6 +124,11 @@ def _load_from_json_content(win): new_win.phase_arrivals = win["phase_arrivals"] new_win.channel_id_2 = win["channel_id_2"] + keys = ["snr_amplitude", "snr_amplitude_threshold", "distance_in_deg"] + for k in keys: + if k in win: + new_win.__dict__[k] = win[k] + return new_win def _get_json_content(self): @@ -147,6 +156,10 @@ def _get_json_content(self): "relative_endtime": self.relative_endtime, "window_weight": self.weight} + keys = ["snr_amplitude", "snr_amplitude_threshold", "distance_in_deg"] + for key in keys: + info[key] = self.__dict__[key] + return info def _get_internal_indices(self, indices): diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 3eea5de..d771002 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -537,9 +537,8 @@ def determine_signal_and_noise_indices(self): "and thus the theoretical arrival times cannot " "be calculated") else: - # self.config.signal_end_index = \ - # self.calculate_signal_end_index() - self.config.signal_end_index = self.observed.stats.npts + self.config.signal_end_index = \ + self.calculate_signal_end_index() self.config._convert_negative_index(npts=self.observed.stats.npts) From 4b40aa74d460450d66ee6eb36d2b012d01a84218 Mon Sep 17 00:00:00 2001 From: lei Date: Tue, 19 May 2020 14:47:47 -0400 Subject: [PATCH 28/33] add more information into window --- src/pyflex/__init__.py | 3 ++- src/pyflex/tests/test_pyflex.py | 6 +++--- src/pyflex/tests/test_window.py | 6 +++++- src/pyflex/window.py | 13 +++++++++++++ src/pyflex/window_selector.py | 5 ++--- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/pyflex/__init__.py b/src/pyflex/__init__.py index 718c6fc..92d5acd 100644 --- a/src/pyflex/__init__.py +++ b/src/pyflex/__init__.py @@ -43,7 +43,8 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -logger.setLevel(logging.WARNING) +#logger.setLevel(logging.WARNING) +logger.setLevel(logging.DEBUG) # Prevent propagating to higher loggers. logger.propagate = 0 # Console log handler. diff --git a/src/pyflex/tests/test_pyflex.py b/src/pyflex/tests/test_pyflex.py index 596e95b..7df2216 100644 --- a/src/pyflex/tests/test_pyflex.py +++ b/src/pyflex/tests/test_pyflex.py @@ -406,7 +406,7 @@ def test_determine_signal_and_noise_indices(): assert ws.config.noise_start_index == 0 assert ws.config.noise_end_index == 1331 assert ws.config.signal_start_index == 1331 - assert ws.config.signal_end_index == 5352 + assert ws.config.signal_end_index == 5349 config.max_time_before_first_arrival = 200 config.max_time_after_last_arrival = 300 @@ -415,7 +415,7 @@ def test_determine_signal_and_noise_indices(): assert ws.config.noise_start_index == 0 assert ws.config.noise_end_index == 1231 assert ws.config.signal_start_index == 1231 - assert ws.config.signal_end_index == 5502 + assert ws.config.signal_end_index == 5499 def test_noise_start_and_end_index(): @@ -470,7 +470,7 @@ def test_selection_mode(): config.selection_mode = "mantle_waves" ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) windows = ws.select_windows() - assert len(windows) == 3 + assert len(windows) == 0 config.selection_mode = "body_and_surface_waves" ws = pyflex.window_selector.WindowSelector(OBS_DATA, SYNTH_DATA, config) diff --git a/src/pyflex/tests/test_window.py b/src/pyflex/tests/test_window.py index 2e61215..9487489 100644 --- a/src/pyflex/tests/test_window.py +++ b/src/pyflex/tests/test_window.py @@ -168,7 +168,11 @@ def test_window_to_dict_and_back(tmpdir): "absolute_endtime": win.absolute_endtime, "relative_starttime": win.relative_starttime, "relative_endtime": win.relative_endtime, - "window_weight": win.weight} + "window_weight": win.weight, + "distance_in_deg": None, + "snr_amplitude": None, + "snr_amplitude_threshold": None + } assert output == expected diff --git a/src/pyflex/window.py b/src/pyflex/window.py index e337d70..ee5e62e 100644 --- a/src/pyflex/window.py +++ b/src/pyflex/window.py @@ -74,6 +74,10 @@ def __init__(self, left, right, center, time_of_first_sample, dt, self.channel_id_2 = channel_id_2 self.phase_arrivals = [] self.weight_function = weight_function + # extra properties + self.snr_amplitude = None + self.snr_amplitude_threshold = None + self.distance_in_deg = None def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -120,6 +124,11 @@ def _load_from_json_content(win): new_win.phase_arrivals = win["phase_arrivals"] new_win.channel_id_2 = win["channel_id_2"] + keys = ["snr_amplitude", "snr_amplitude_threshold", "distance_in_deg"] + for k in keys: + if k in win: + new_win.__dict__[k] = win[k] + return new_win def _get_json_content(self): @@ -147,6 +156,10 @@ def _get_json_content(self): "relative_endtime": self.relative_endtime, "window_weight": self.weight} + keys = ["snr_amplitude", "snr_amplitude_threshold", "distance_in_deg"] + for key in keys: + info[key] = self.__dict__[key] + return info def _get_internal_indices(self, indices): diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index 3eea5de..d771002 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -537,9 +537,8 @@ def determine_signal_and_noise_indices(self): "and thus the theoretical arrival times cannot " "be calculated") else: - # self.config.signal_end_index = \ - # self.calculate_signal_end_index() - self.config.signal_end_index = self.observed.stats.npts + self.config.signal_end_index = \ + self.calculate_signal_end_index() self.config._convert_negative_index(npts=self.observed.stats.npts) From 5573b1984a43e08b2aa691a3cabb6416d9913063 Mon Sep 17 00:00:00 2001 From: lei Date: Mon, 1 Mar 2021 10:52:15 -0500 Subject: [PATCH 29/33] improve window selection region based on arrival time mode --- src/pyflex/window_selector.py | 39 ++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/pyflex/window_selector.py b/src/pyflex/window_selector.py index d771002..d7b1d40 100644 --- a/src/pyflex/window_selector.py +++ b/src/pyflex/window_selector.py @@ -731,7 +731,32 @@ def _prepare_min_max_timebox(self, min_time, max_time, srate): logger.debug("selection_timebox index range: {} - {} / {}".format( il, ir, len(timebox))) + self.selection_timebox = timebox + return timebox + + def _prepare_exclude_surface_wave_timebox(self, min_time, max_time, + srate, offset): + logger.debug("selection_timebox exclude surface waves") + + # get the surface windows first + self._prepare_surface_wave_timebox(srate, offset) + + # flip the sign to reject surface windoes + timebox = self.selection_timebox + timebox = ~timebox + + # set the min_time and max_time range to non-selectable + i1 = int(min_time * srate) + timebox[:i1] = False + + i2 = int(max_time * srate) + timebox[i2:] = False + + logger.debug("Selectable region coverage percentage: {}/{}".format( + timebox.sum(), len(timebox))) + self.selection_timebox = timebox + return timebox def _prepare_surface_wave_timebox(self, srate, offset): logger.debug("selection_timebox using surface waves") @@ -746,12 +771,13 @@ def _prepare_surface_wave_timebox(self, srate, offset): timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) for arr in arrivals: il = int((arr[0] + offset - self.config.min_period) * srate) - ir = int((arr[1] + offset + self.config.min_period) * srate) + ir = int((arr[1] + offset + 2.5 * self.config.min_period) * srate) timebox[il:(ir+1)] = 1 - logger.debug("Selectable region percentage: {}/{}".format( + logger.debug("Selectable region coverage percentage: {}/{}".format( timebox.sum(), len(timebox))) self.selection_timebox = timebox + return timebox def _prepare_phase_timebox(self, phase_list, srate, buffer_time, offset): logger.debug("Selection_timebox using phases: {}".format(phase_list)) @@ -777,6 +803,8 @@ def _prepare_phase_timebox(self, phase_list, srate, buffer_time, offset): timebox.sum(), len(timebox))) self.selection_timebox = timebox + return timebox + def reject_on_selection_mode(self): """ Reject based on selection mode. @@ -804,10 +832,15 @@ def reject_on_selection_mode(self): first_arrival = self.ttimes[0]["time"] - if select_mode in ["all_waves", "body_and_mantle_waves"]: + if select_mode == "all_waves": min_time = first_arrival - buffer_time + offset max_time = tr_timelen self._prepare_min_max_timebox(min_time, max_time, srate) + elif select_mode == "body_and_mantle_waves": + min_time = first_arrival - buffer_time + offset + max_time = tr_timelen + self._prepare_exclude_surface_wave_timebox( + min_time, max_time, srate, offset) elif select_mode == "body_and_surface_waves": min_time = first_arrival - buffer_time + offset max_time = surface_end + buffer_time + offset From b844db07fdb1328ad51b099c4ab4a3d5bb14aea6 Mon Sep 17 00:00:00 2001 From: Lucas Sawade Date: Wed, 13 Sep 2023 19:21:46 -0400 Subject: [PATCH 30/33] Finally the tests are passing --- pyflex/__init__.py | 1 - pyflex/config.py | 4 +- pyflex/tests/test_pyflex.py | 2 + pyflex/tests/test_window_selector.py | 3 +- pyflex/window_selector.py | 80 +++++++++++++--------------- 5 files changed, 44 insertions(+), 46 deletions(-) diff --git a/pyflex/__init__.py b/pyflex/__init__.py index a9da4df..4b777b8 100644 --- a/pyflex/__init__.py +++ b/pyflex/__init__.py @@ -38,7 +38,6 @@ class PyflexWarning(UserWarning): # Setup the logger. logger = logging.getLogger("pyflex") -#logger.setLevel(logging.WARNING) logger.setLevel(logging.DEBUG) # Prevent propagating to higher loggers. logger.propagate = 0 diff --git a/pyflex/config.py b/pyflex/config.py index 691100d..ad4baec 100644 --- a/pyflex/config.py +++ b/pyflex/config.py @@ -24,13 +24,13 @@ def __init__(self, min_period, max_period, stalta_waterlevel=0.07, s2n_limit=1.5, s2n_limit_energy=1.5, min_surface_wave_velocity=3.0, max_surface_wave_velocity=4.2, - max_time_before_first_arrival=50.0, + max_time_before_first_arrival=None, max_time_after_last_arrival=None, c_0=1.0, c_1=1.5, c_2=0.0, c_3a=4.0, c_3b=2.5, c_4a=2.0, c_4b=6.0, check_global_data_quality=False, snr_integrate_base=3.5, snr_max_base=3.0, noise_start_index=0, noise_end_index=None, - signal_start_index=None, signal_end_index=-1, + signal_start_index=None, signal_end_index=None, window_weight_fct=None, window_signal_to_noise_type="amplitude", resolution_strategy="interval_scheduling", diff --git a/pyflex/tests/test_pyflex.py b/pyflex/tests/test_pyflex.py index 3acf738..31748d8 100644 --- a/pyflex/tests/test_pyflex.py +++ b/pyflex/tests/test_pyflex.py @@ -424,6 +424,8 @@ def test_determine_signal_and_noise_indices(): assert ws.config.signal_end_index == 5499 + + def test_noise_start_and_end_index(): config = pyflex.Config( min_period=50.0, max_period=150.0, diff --git a/pyflex/tests/test_window_selector.py b/pyflex/tests/test_window_selector.py index 10b3b25..387a4fc 100644 --- a/pyflex/tests/test_window_selector.py +++ b/pyflex/tests/test_window_selector.py @@ -105,13 +105,14 @@ def test_return_rejected_windows(): min_period=50.0, max_period=150.0, stalta_waterlevel=0.08, tshift_acceptance_level=15.0, dlna_acceptance_level=1.0, cc_acceptance_level=0.80, + max_time_before_first_arrival=50.0, c_0=0.7, c_1=4.0, c_2=0.0, c_3a=1.0, c_3b=2.0, c_4a=3.0, c_4b=10.0, selection_mode=None) ws = pyflex.WindowSelector(observed=OBS_DATA, synthetic=SYNTH_DATA, config=config) ws.select_windows() - assert len(ws.windows) == False + assert len(ws.rejects) > 0 assert len(ws.rejects["min_length"]) == 10 assert len(ws.rejects["water_level"]) == 1617 diff --git a/pyflex/window_selector.py b/pyflex/window_selector.py index 5b13037..a21c8a8 100644 --- a/pyflex/window_selector.py +++ b/pyflex/window_selector.py @@ -294,8 +294,12 @@ def calculate_preliminiaries(self): self.stalta = sta_lta(self.synthetic_envelope, self.observed.stats.delta, self.config.min_period) + self.peaks, self.troughs = utils.find_local_extrema(self.stalta) + logger.debug("Found %i peaks and %i troughs." % ( + len(self.peaks), len(self.troughs))) + if not len(self.peaks) and len(self.troughs): return @@ -305,37 +309,26 @@ def reject_peaks_and_troughs_not_in_signal_region(self): This will save us huge amount of time by rejecting a large number of non-sense peaks and troughs. """ + if self.ttimes: - #offset = self.event.origin_time - self.observed.stats.starttime - #min_time = self.ttimes[0]["time"] - \ - # self.config.max_time_before_first_arrival + offset - #min_idx = int(min_time / self.observed.stats.delta) - min_idx = self.config.signal_start_index - - #dist_in_km = obspy.geodetics.calc_vincenty_inverse( - # self.station.latitude, self.station.longitude, - # self.event.latitude, self.event.longitude)[0] / 1000.0 - #max_time = dist_in_km / self.config.min_surface_wave_velocity + \ - # offset + self.config.max_period - #max_idx = int(max_time / self.observed.stats.delta) - max_idx = self.config.signal_end_index + + offset = self.event.origin_time - self.observed.stats.starttime + min_time = self.ttimes[0]["time"] - \ + self.config.max_time_before_first_arrival + offset + min_idx = int(min_time / self.observed.stats.delta) + + dist_in_km = obspy.geodetics.calc_vincenty_inverse( + self.station.latitude, self.station.longitude, + self.event.latitude, self.event.longitude)[0] / 1000.0 + max_time = dist_in_km / self.config.min_surface_wave_velocity + \ + offset + self.config.max_period + max_idx = int(max_time / self.observed.stats.delta) # Reject all peaks and troughs before the minimal allowed start # time and after the maximum allowed end time. first_trough, last_trough = self.troughs[0], self.troughs[-1] - # Reject all peaks not in the signal region. This kind of - # rejection will reduce the window counts and spedd up - # the processing speed - self.peaks = self.peaks[(self.peaks >= min_idx) & - (self.peaks <= max_idx)] - # Reject all troughs before the minimal allowed start - # time and after the maximum allowed end time. - sampling_rate = self.observed.stats.sampling_rate - loose_npts = 2 * self.config.min_period * sampling_rate - min_idx_2 = self.config.signal_start_index - loose_npts - max_idx_2 = self.config.signal_end_index + loose_npts - self.troughs = self.troughs[(self.troughs >= min_idx_2) & - (self.troughs <= max_idx_2)] + self.troughs = self.troughs[(self.troughs >= min_idx) & + (self.troughs <= max_idx)] # If troughs have been removed, readd them add the boundaries. if len(self.troughs): @@ -347,10 +340,12 @@ def reject_peaks_and_troughs_not_in_signal_region(self): self.troughs = np.concatenate([ self.troughs, np.array([max_idx], dtype=self.troughs.dtype)]) - # Make sure peaks are inside the troughs! - min_trough, max_trough = self.troughs[0], self.troughs[-1] - self.peaks = self.peaks[(self.peaks > min_trough) & - (self.peaks < max_trough)] + + # Make sure peaks are inside the troughs! + min_trough, max_trough = self.troughs[0], self.troughs[-1] + self.peaks = self.peaks[(self.peaks > min_trough) & + (self.peaks < max_trough)] + def __print_remaining_windows(self): logger.debug("Remaining windows: %d" % (len(self.windows))) @@ -374,6 +369,9 @@ def select_windows(self): # Calculate some preliminaries measurements self.calculate_preliminiaries() + # Reject peaks and troughs not in the signal region + self.reject_peaks_and_troughs_not_in_signal_region() + # Perform all window selection steps. self.initial_window_selection() @@ -392,15 +390,14 @@ def select_windows(self): logger.warning(msg) warnings.warn(msg, PyflexWarning) - # self.reject_peaks_and_troughs_not_in_signal_region() - + # Determine SNR indeces self.determine_signal_and_noise_indices() if self.config.check_global_data_quality: if not self.check_data_quality(): return [] # Reject windows in the noise region - # self.reject_on_noise_region() + self.reject_on_noise_region() self.reject_windows_based_on_minimum_length() self.reject_on_minima_water_level() @@ -543,7 +540,7 @@ def determine_signal_and_noise_indices(self): self.config._convert_negative_index(npts=self.observed.stats.npts) - logger.info("Noise index [%s, %s]; signal index [%s, %s]" % ( + logger.debug("Noise index [%s, %s]; signal index [%s, %s]" % ( self.config.noise_start_index, self.config.noise_end_index, self.config.signal_start_index, @@ -705,18 +702,14 @@ def calculate_ttimes(self): tts = self.taupy_model.get_travel_times( source_depth_in_km=self.event.depth_in_m / 1000.0, distance_in_degree=self.dist_in_deg) + logger.debug("source depth: {:.2f} km".format( self.event.depth_in_m / 1000.0)) + self.ttimes = [{"time": _i.time, "name": _i.name} for _i in tts] + logger.info("Calculated travel times.") - #logger.debug("{}".format(self.ttimes)) - #tts2 = self.taupy_model.get_travel_times( - # source_depth_in_km=self.event.depth_in_m / 1000.0, - # distance_in_degree=self.dist_in_deg, - # phase_list=["ScS", "sScS", "ScSScS", "sScSScS"] - #) - #logger.debug("ScS arrivals: {}".format(tts2)) def reject_on_noise_region(self): """ @@ -922,13 +915,16 @@ def initial_window_selection(self): Find all possible windows. This is equivalent to the setup_M_L_R() function in flexwin. """ - for peak in self.peaks: + for _i, peak in enumerate(self.peaks): + # only continue if there are available minima on either side if peak <= self.troughs[0] or peak >= self.troughs[-1]: continue + # only continue if this maximum is above the water level if self.stalta[peak] <= self.config.stalta_waterlevel[peak]: continue + smaller_troughs = self.troughs[self.troughs < peak] larger_troughs = self.troughs[self.troughs > peak] From c876a8a94b415c348effe04b3770241216426d87 Mon Sep 17 00:00:00 2001 From: Lucas Sawade Date: Thu, 14 Sep 2023 06:16:27 -0400 Subject: [PATCH 31/33] removed setup.py --- setup.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 setup.py diff --git a/setup.py b/setup.py deleted file mode 100644 index 6068493..0000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() From f70f22015aaede8a2e719007882fb8b924a0d383 Mon Sep 17 00:00:00 2001 From: Lucas Sawade Date: Tue, 28 Nov 2023 11:05:35 -0500 Subject: [PATCH 32/33] Fixed a bug, that made it hard to select multi orbit arrivals. --- pyflex/window_selector.py | 58 +++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/pyflex/window_selector.py b/pyflex/window_selector.py index a21c8a8..20bec2e 100644 --- a/pyflex/window_selector.py +++ b/pyflex/window_selector.py @@ -312,17 +312,31 @@ def reject_peaks_and_troughs_not_in_signal_region(self): if self.ttimes: - offset = self.event.origin_time - self.observed.stats.starttime - min_time = self.ttimes[0]["time"] - \ - self.config.max_time_before_first_arrival + offset - min_idx = int(min_time / self.observed.stats.delta) + if self.config.selection_mode \ + and "surface" in self.config.selection_mode: + # For the surface wave the selection of troughs will be + # taken care of by the surface wave selection box + min_time = 0 + max_time = self.observed.stats.endtime - \ + self.observed.stats.starttime + min_idx = 0 + max_idx = self.observed.stats.npts + + + else: - dist_in_km = obspy.geodetics.calc_vincenty_inverse( - self.station.latitude, self.station.longitude, - self.event.latitude, self.event.longitude)[0] / 1000.0 - max_time = dist_in_km / self.config.min_surface_wave_velocity + \ - offset + self.config.max_period - max_idx = int(max_time / self.observed.stats.delta) + offset = self.event.origin_time - self.observed.stats.starttime + min_time = self.ttimes[0]["time"] - \ + self.config.max_time_before_first_arrival + offset + min_idx = int(min_time / self.observed.stats.delta) + + dist_in_km = obspy.geodetics.calc_vincenty_inverse( + self.station.latitude, self.station.longitude, + self.event.latitude, self.event.longitude)[0] / 1000.0 + + max_time = dist_in_km / self.config.min_surface_wave_velocity + \ + offset + self.config.max_period + max_idx = int(max_time / self.observed.stats.delta) # Reject all peaks and troughs before the minimal allowed start # time and after the maximum allowed end time. @@ -362,6 +376,9 @@ def select_windows(self): Launch the window selection. """ # Fill self.ttimes. + logger.debug(f"======================================================") + logger.debug(f"Start selection for {self.observed.id}") + logger.debug(f"======================================================") if self.event and self.station: self.calculate_distance() self.calculate_ttimes() @@ -375,18 +392,20 @@ def select_windows(self): # Perform all window selection steps. self.initial_window_selection() + # Reject windows based on traveltime if event and station # information is given. This will also fill self.ttimes. if self.event and self.station: if self.config.selection_mode is not None: # Base on specific selection mode self.reject_on_selection_mode() + pass else: # Based on basic traveltimes self.reject_on_traveltimes() else: msg = "No rejection based on traveltime possible. Event and/or " \ - "station information is not available." + "station information is not available." logger.warning(msg) warnings.warn(msg, PyflexWarning) @@ -485,6 +504,7 @@ def calculate_signal_end_index(self): end index based the first arrival(event and station information required). """ + offset = self.event.origin_time - self.observed.stats.starttime # signal end index surface_wave_arrival = \ @@ -501,7 +521,15 @@ def calculate_signal_end_index(self): self.observed.stats.sampling_rate) npts = self.observed.stats.npts - signal_end_index = min(signal_end_index, npts) + + if self.config.selection_mode: + if "surface" in self.config.selection_mode: + # This is ok, because a timebox will be computed anyways + # to exclude anything outside specific regions! + signal_end_index = npts + else: + signal_end_index = min(signal_end_index, npts) + return signal_end_index def determine_signal_and_noise_indices(self): @@ -783,11 +811,12 @@ def _prepare_surface_wave_timebox(self, srate, offset): len(arrivals))) timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) - for arr in arrivals: + + for _i, arr in enumerate(arrivals): il = int((arr[0] + offset - self.config.min_period) * srate) ir = int((arr[1] + offset + 2.5 * self.config.min_period) * srate) + logger.debug(f"Arrival {_i} (min, max): ({il}, {ir})") timebox[il:(ir+1)] = 1 - logger.debug("Selectable region coverage percentage: {}/{}".format( timebox.sum(), len(timebox))) self.selection_timebox = timebox @@ -997,6 +1026,7 @@ def schedule_weighted_intervals(self): """ Run the weighted interval scheduling. """ + self.windows = schedule_weighted_intervals(self.windows) logger.info("Weighted interval schedule optimization retained %i " From d800bc5da018ca9a93288ca670bf101244660ef5 Mon Sep 17 00:00:00 2001 From: Lucas Sawade Date: Thu, 25 Jan 2024 19:38:21 -0500 Subject: [PATCH 33/33] Update bool --- pyflex/window_selector.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyflex/window_selector.py b/pyflex/window_selector.py index 20bec2e..97bfd00 100644 --- a/pyflex/window_selector.py +++ b/pyflex/window_selector.py @@ -766,7 +766,7 @@ def _prepare_min_max_timebox(self, min_time, max_time, srate): logger.debug("selection_timebox min/max time: {:.2f} {:.2f}" "".format(min_time, max_time)) - timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + timebox = np.zeros(self.observed.stats.npts, dtype=bool) il = int(min_time * srate) ir = int(max_time * srate) timebox[il:(ir+1)] = 1 @@ -810,7 +810,7 @@ def _prepare_surface_wave_timebox(self, srate, offset): logger.debug("Number of surface wave arrivals: {}".format( len(arrivals))) - timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + timebox = np.zeros(self.observed.stats.npts, dtype=bool) for _i, arr in enumerate(arrivals): il = int((arr[0] + offset - self.config.min_period) * srate) @@ -834,7 +834,7 @@ def _prepare_phase_timebox(self, phase_list, srate, buffer_time, offset): phase_list=phase_list ) - timebox = np.zeros(self.observed.stats.npts, dtype=np.bool) + timebox = np.zeros(self.observed.stats.npts, dtype=bool) for t in tts: t_left = t.time - buffer_time + offset il = int(t_left * srate)