def main(segment, config): '''main function''' # annoying print statementin obspy 1.1.1 when calling the function 'psd' # (see below) and when adding a trace shorter than # the ppsd_length: workaround? redirect to stderr (which is captured by the caller): temp = sys.stdout try: sys.stdout = sys.stderr stream = segment.stream(True) assert1trace( stream) # raise and return if stream has more than one trace # raw_trace = stream[0] ret = get_psd_values_df(segment, config) # pd.concat(data, sort=False, ignore_index=True, copy=True, axis=0) ret['amplitude_ratio'] = ampratio(segment.stream()[0]) ret['event_id'] = segment.event_id ret['station_id'] = segment.station.id ret['event_time'] = segment.event.time # store channel's channel via data_seed_id (might be faster): # calculate it here so in case of error we avoid unnecessary calculations net_sta_loc_cha = segment.data_seed_id.split('.') ret['location_code'] = net_sta_loc_cha[2] ret['channel_code'] = net_sta_loc_cha[3] ret['magnitude'] = segment.event.magnitude ret['distance_km'] = segment.event_distance_km ret['dataset_id'] = config['dataset_id'] return ret finally: sys.stdout = temp
def main2(segment, config): '''calls _main with the normal inventory and all possible wrong inventories''' # annoying print statementin obspy 1.1.1 when calling the function 'psd' # (see below) and when adding a trace shorter than # the ppsd_length: workaround? redirect to stderr (which is captured by the caller): temp = sys.stdout try: sys.stdout = sys.stderr stream = segment.stream(True) assert1trace( stream) # raise and return if stream has more than one trace raw_trace = stream[0].copy() # store channel's channel via data_seed_id (might be faster): # calculate it here so in case of error we avoid unnecessary calculations channel_code = segment.data_seed_id.split('.')[3] loc_code = segment.data_seed_id.split('.')[2] # compute amplitude ratio only once on the raw trace: amp_ratio = ampratio(raw_trace) # if amp_ratio >= config['amp_ratio_threshold']: # saturated = True # @UnusedVariable data = [] # bandpass the trace, according to the event magnitude. # This modifies the segment.stream() permanently: data.append(_main(segment, config, raw_trace, segment.inventory())) ret = pd.concat(data, sort=False, ignore_index=True, copy=True, axis=0) ret['amplitude_ratio'] = amp_ratio ret['event_id'] = segment.event_id ret['station_id'] = segment.station.id ret['event_time'] = segment.event.time ret['location_code'] = loc_code ret['channel_code'] = channel_code ret['magnitude'] = segment.event.magnitude ret['distance_km'] = segment.event_distance_km return ret finally: sys.stdout = temp
def main(segment, config): """{{ PROCESS_PY_MAINFUNC | indent }} """ stream = segment.stream() assert1trace(stream) # raise and return if stream has more than one trace trace = stream[0] # work with the (surely) one trace now # discard saturated signals (according to the threshold set in the config file): amp_ratio = ampratio(trace) if amp_ratio >= config['amp_ratio_threshold']: raise ValueError('possibly saturated (amp. ratio exceeds)') # bandpass the trace, according to the event magnitude. # WARNING: this modifies the segment.stream() permanently! # If you want to preserve the original stream, store trace.copy() beforehand. # Also, use a 'try catch': sometimes Inventories are corrupted and obspy raises # a TypeError, which would break the WHOLE processing execution. # Raising a ValueError will stop the execution of the currently processed # segment only (logging the error message): try: trace = bandpass_remresp(segment, config) except TypeError as type_error: raise ValueError("Error in 'bandpass_remresp': %s" % str(type_error)) spectra = signal_noise_spectra(segment, config) normal_f0, normal_df, normal_spe = spectra['Signal'] noise_f0, noise_df, noise_spe = spectra['Noise'] evt = segment.event fcmin = mag2freq(evt.magnitude) fcmax = config['preprocess'][ 'bandpass_freq_max'] # used in bandpass_remresp snr_ = snr(normal_spe, noise_spe, signals_form=config['sn_spectra']['type'], fmin=fcmin, fmax=fcmax, delta_signal=normal_df, delta_noise=noise_df) snr1_ = snr(normal_spe, noise_spe, signals_form=config['sn_spectra']['type'], fmin=fcmin, fmax=1, delta_signal=normal_df, delta_noise=noise_df) snr2_ = snr(normal_spe, noise_spe, signals_form=config['sn_spectra']['type'], fmin=1, fmax=10, delta_signal=normal_df, delta_noise=noise_df) snr3_ = snr(normal_spe, noise_spe, signals_form=config['sn_spectra']['type'], fmin=10, fmax=fcmax, delta_signal=normal_df, delta_noise=noise_df) if snr_ < config['snr_threshold']: raise ValueError('low snr %f' % snr_) # calculate cumulative cum_labels = [0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99] cum_trace = cumsumsq( trace, normalize=True, copy=True) # copy=True prevent original trace from being modified cum_times = timeswhere(cum_trace, *cum_labels) # double event try: (score, t_double, tt1, tt2) = \ get_multievent_sg( cum_trace, cum_times[1], cum_times[-2], config['savitzky_golay'], config['multievent_thresholds'] ) except IndexError as _ierr: raise ValueError("Error in 'get_multievent_sg': %s" % str(_ierr)) if score in {1, 3}: raise ValueError('Double event detected %d %s %s %s' % (score, t_double, tt1, tt2)) # calculate PGA and times of occurrence (t_PGA): # note: you can also provide tstart tend for slicing t_PGA, PGA = maxabs(trace, cum_times[1], cum_times[-2]) trace_int = trace.copy() trace_int.integrate() t_PGV, PGV = maxabs(trace_int, cum_times[1], cum_times[-2]) meanoff = meanslice(trace_int, 100, cum_times[-1], trace_int.stats.endtime) # calculates amplitudes at the frequency bins given in the config file: required_freqs = config['freqs_interp'] ampspec_freqs = normal_f0 + np.arange(len(normal_spe)) * normal_df required_amplitudes = np.interp(np.log10(required_freqs), np.log10(ampspec_freqs), normal_spe) / segment.sample_rate # compute synthetic WA. trace_wa = synth_wood_anderson(segment, config, trace.copy()) t_WA, maxWA = maxabs(trace_wa) # write stuff to csv: ret = OrderedDict() ret['snr'] = snr_ ret['snr1'] = snr1_ ret['snr2'] = snr2_ ret['snr3'] = snr3_ for cum_lbl, cum_t in zip(cum_labels[slice(1, 8, 3)], cum_times[slice(1, 8, 3)]): ret['cum_t%f' % cum_lbl] = float( cum_t) # convert cum_times to float for saving ret['dist_deg'] = segment.event_distance_deg # dist ret['dist_km'] = d2km(segment.event_distance_deg) # dist_km # t_PGA is a obspy UTCDateTime. This type is not supported in HDF output, thus # convert it to Python datetime. Note that in CSV output, the value will be written as # str(t_PGA.datetime): another option might be to store it as string # with str(t_PGA) (returns the iso-formatted string, supported in all output formats): ret['t_PGA'] = t_PGA.datetime # peak info ret['PGA'] = PGA # (for t_PGV, see note above for t_PGA) ret['t_PGV'] = t_PGV.datetime # peak info ret['PGV'] = PGV # (for t_WA, see note above for t_PGA) ret['t_WA'] = t_WA.datetime ret['maxWA'] = maxWA ret['channel'] = segment.channel.channel ret['channel_component'] = segment.channel.channel[-1] # event metadata: ret['ev_id'] = segment.event.id ret['ev_lat'] = segment.event.latitude ret['ev_lon'] = segment.event.longitude ret['ev_dep'] = segment.event.depth_km ret['ev_mag'] = segment.event.magnitude ret['ev_mty'] = segment.event.mag_type # station metadata: ret['st_id'] = segment.station.id ret['st_name'] = segment.station.station ret['st_net'] = segment.station.network ret['st_lat'] = segment.station.latitude ret['st_lon'] = segment.station.longitude ret['st_ele'] = segment.station.elevation ret['score'] = score ret['d2max'] = float(tt1) ret['offset'] = np.abs(meanoff / PGV) for freq, amp in zip(required_freqs, required_amplitudes): ret['f_%.5f' % freq] = float(amp) return ret
def main2(segment, config): '''calls _main with the normal inventory and all possible wrong inventories''' # annoying print statementin obspy 1.1.1 when calling the function 'psd' # (see below) and when adding a trace shorter than # the ppsd_length: workaround? redirect to stderr (which is captured by the caller): temp = sys.stdout try: sys.stdout = sys.stderr stream = segment.stream(True) assert1trace(stream) # raise and return if stream has more than one trace raw_trace = stream[0].copy() trace = stream[0] # work with the (surely) one trace now # compute amplitude ratio only once on the raw trace: amp_ratio = ampratio(trace) # if amp_ratio >= config['amp_ratio_threshold']: # saturated = True # @UnusedVariable data = [] # bandpass the trace, according to the event magnitude. # This modifies the segment.stream() permanently: trace = _bandpass_remresp(segment, config, trace, segment.inventory()) data.append(_main(segment, config, raw_trace.copy(), segment.inventory())) data[-1]['amplitude_ratio'] = amp_ratio # add gain (1). Decide whether to compute gain x2,10,100 or x1/2.1/10,1/100 # (not both, try to speed up a bit the computations) # "randomly" according to the segment id (even or odd) gain_factors = config['stage_gain_factors'] if segment.id % 2 == 0: gain_factors = gain_factors[:3] else: gain_factors = gain_factors[3:] for gain_factor in gain_factors: newtrace = trace.copy() newtrace.data *= float(gain_factor) stream[0] = newtrace assert segment.stream()[0] is newtrace # need to change alkso the raw trace for the noisepsd, otherwise # we calculate the same psd as if we did not change the gain: raw_trace_ = raw_trace.copy() raw_trace_dtype_ = raw_trace_.data.dtype raw_trace_.data = raw_trace_.data * float(gain_factor) if np.issubdtype(raw_trace_dtype_, np.integer): raw_trace_.data = (0.5 + raw_trace_.data).astype(raw_trace_dtype_) data.append(_main(segment, config, raw_trace_, segment.inventory())) data[-1]['outlier'] = 1 data[-1]['modified'] = "STAGEGAIN:X%s" % str(gain_factor) data[-1]['amplitude_ratio'] = amp_ratio # acceleromters/velocimeters: if segment.station.id in config['station_ids_both_accel_veloc']: # reload inventory (takes more time, but we won't modify cached version): inventory = get_inventory(segment.station) cha_obj = get_cha_obj(segment, inventory) resp_tmp = cha_obj.response for other_cha in get_other_chan_objs(segment, inventory): cha_obj.response = other_cha.response # force reloading the segment stream: stream = segment.stream(True) # re-apply bandpass with the "wrong" inventory # (modifying segment.stream() inplace): _test_trace = _bandpass_remresp(segment, config, stream[0], inventory) assert _test_trace is segment.stream()[0] data.append(_main(segment, config, raw_trace.copy(), inventory)) data[-1]['outlier'] = 1 data[-1]['modified'] = "CHARESP:%s" % other_cha.code data[-1]['amplitude_ratio'] = amp_ratio cha_obj.response = resp_tmp if segment.station.id in config['station_ids_with_wrong_local_inventory']: channels_ = config['station_ids_with_wrong_local_inventory'][segment.station.id] filename = channels_.get(segment.data_seed_id, None) if filename is None: raise ValueError('%s not found in wrong inventories dict' % segment.data_seed_id) if filename is not None: inventories_dir = config['inventories_dir'] wrong_inventory = read_inventory(os.path.join(os.getcwd(), inventories_dir, filename)) # force reloading the segment stream: stream = segment.stream(True) # re-apply bandpass with the "wrong" inventory # (modifying segment.stream() inplace): _test_trace = _bandpass_remresp(segment, config, stream[0], wrong_inventory) assert _test_trace is segment.stream()[0] data.append(_main(segment, config, raw_trace.copy(), wrong_inventory)) data[-1]['outlier'] = 1 data[-1]['modified'] = "INVFILE:%s" % filename data[-1]['amplitude_ratio'] = amp_ratio return pd.DataFrame(data) finally: sys.stdout = temp
def main2(segment, config): '''calls _main with the normal inventory and all possible wrong inventories''' # annoying print statementin obspy 1.1.1 when calling the function 'psd' # (see below) and when adding a trace shorter than # the ppsd_length: workaround? redirect to stderr (which is captured by the caller): temp = sys.stdout try: sys.stdout = sys.stderr stream = segment.stream(True) assert1trace( stream) # raise and return if stream has more than one trace raw_trace = stream[0].copy() # store channel's channel via data_seed_id (might be faster): # calculate it here so in case of error we avoid unnecessary calculations channel_code = segment.data_seed_id.split('.')[3] location_code = segment.data_seed_id.split('.')[2] # compute amplitude ratio only once on the raw trace: amp_ratio = ampratio(raw_trace) # if amp_ratio >= config['amp_ratio_threshold']: # saturated = True # @UnusedVariable # data = [] # bandpass the trace, according to the event magnitude. # This modifies the segment.stream() permanently: # data.append(_main(segment, config, raw_trace, segment.inventory())) # add gain (1). Decide whether to compute gain x2,10,100 or x1/2.1/10,1/100 # (not both, try to speed up a bit the computations) # "randomly" according to the segment id (even or odd) # gain_factors = config['stage_gain_factors'] # if segment.id % 2 == 0: # gain_factors = gain_factors[:3] # else: # gain_factors = gain_factors[3:] # for gain_factor in gain_factors: # # need to change alkso the raw trace for the noisepsd, otherwise # # we calculate the same psd as if we did not change the gain: # raw_trace_ = raw_trace.copy() # raw_trace_dtype_ = raw_trace_.data.dtype # raw_trace_.data = raw_trace_.data * float(gain_factor) # if np.issubdtype(raw_trace_dtype_, np.integer): # raw_trace_.data = (0.5 + raw_trace_.data).astype(raw_trace_dtype_) # data.append(_main(segment, config, raw_trace_, segment.inventory())) # data[-1]['outlier'] = True # data[-1]['modified'] = "STAGEGAIN:X%s" % str(gain_factor) # # # acceleromters/velocimeters: # if segment.station.id in config['station_ids_both_accel_veloc']: # # reload inventory (takes more time, but we won't modify cached version): # inventory = get_inventory(segment.station) # cha_obj = get_cha_obj(segment, inventory) # resp_tmp = cha_obj.response # for other_cha in get_other_chan_objs(segment, inventory): # cha_obj.response = other_cha.response # data.append(_main(segment, config, raw_trace, inventory)) # data[-1]['outlier'] = True # data[-1]['modified'] = "CHARESP:%s" % other_cha.code # cha_obj.response = resp_tmp # # if segment.station.id in config['station_ids_with_wrong_local_inventory']: # channels_ = config['station_ids_with_wrong_local_inventory'][segment.station.id] # filename = channels_.get(segment.data_seed_id, None) # if filename is None: # raise ValueError('%s not found in wrong inventories dict' % segment.data_seed_id) # if filename is not None: # inventories_dir = config['inventories_dir'] # wrong_inventory = read_inventory(os.path.join(os.getcwd(), inventories_dir, # filename)) # data.append(_main(segment, config, raw_trace, wrong_inventory)) # data[-1]['outlier'] = True # data[-1]['modified'] = "INVFILE:%s" % filename ret = _main(segment, config, raw_trace, segment.inventory()) # data[-1]['outlier'] = True # ret = pd.concat(data, sort=False, ignore_index=True, copy=True, axis=0) ret['amplitude_ratio'] = amp_ratio ret['event_id'] = segment.event_id ret['station_id'] = segment.station.id ret['event_time'] = segment.event.time ret['channel_code'] = channel_code ret['location_code'] = location_code ret['magnitude'] = segment.event.magnitude ret['distance_km'] = segment.event_distance_km return ret finally: sys.stdout = temp