def _qc_event( event: Event, min_stations: int = None, auto_picks: bool = True, auto_event: bool = True, event_type: Union[list, str] = None, ) -> tuple: """ QC an individual event - removes picks in place. Returns ------- tuple of (event: Event, keep: bool) """ if event_type is not None and isinstance(event_type, str): event_type = [event_type] if event_type is not None and event.event_type not in event_type: return event, False elif not auto_event: if "manual" not in [ori.evaluation_mode for ori in event.origins]: return event, False if not auto_picks: pick_ids_to_remove = [ p.resource_id for p in event.picks if p.evaluation_mode == "automatic" ] # remove arrivals and amplitudes and station_magnitudes event.picks = [ p for p in event.picks if p.resource_id not in pick_ids_to_remove ] event = remove_unreferenced(event)[0] stations = {p.waveform_id.station_code for p in event.picks} if len(stations) < min_stations: return event, False return event, True
def __init__(self, parent=None, evtdata=None): self._parent = parent if self.getParent(): self.comp = parent.getComponent() else: self.comp = 'Z' self.wfdata = Stream() self._new = False if isinstance(evtdata, ObsPyEvent) or isinstance(evtdata, Event): pass elif isinstance(evtdata, dict): evt = readPILOTEvent(**evtdata) evtdata = evt elif isinstance(evtdata, str): try: cat = read_events(evtdata) if len(cat) is not 1: raise ValueError('ambiguous event information for file: ' '{file}'.format(file=evtdata)) evtdata = cat[0] except TypeError as e: if 'Unknown format for file' in e.message: if 'PHASES' in evtdata: picks = picksdict_from_pilot(evtdata) evtdata = ObsPyEvent() evtdata.picks = picks_from_picksdict(picks) elif 'LOC' in evtdata: raise NotImplementedError('PILOT location information ' 'read support not yet ' 'implemeted.') else: raise e else: raise e else: # create an empty Event object self.setNew() evtdata = ObsPyEvent() evtdata.picks = [] self.evtdata = evtdata self.wforiginal = None self.cuttimes = None self.dirty = False
latitude=str(lat[x]), depth=str(dep[x])) magnitude = Magnitude(mag = ml[x], magnitude_type = "M", origin_id = (str(orid[x]))) arrival = Arrival(pick_id = rd, phase = str(phase[x])) event.picks.append(picks) event.origins.append(origin) origin.arrivals.append(arrival) event.magnitudes.append(magnitude) db_catalog.append(event) #Only include picks for stations used all_picks=[] for event in db_catalog: stations = ['KCT', 'KMPB', 'KCR', 'KHMB', 'KCS', 'KCO', 'KMR', 'KPP'] event.picks = [pick for pick in event.picks if pick.waveform_id.station_code in stations] all_picks+= [(pick.waveform_id.station_code, pick.waveform_id.channel_code) for pick in event.picks] new_catalog=Catalog() for event in db_catalog: event.picks = [pick for pick in event.picks if (pick.waveform_id.station_code, pick.waveform_id.channel_code) in all_picks] new_catalog.append(event) # count number of picks for each event in catalog n_picks = [len(event.picks) for event in new_catalog] #Save catalog new_catalog.write("DB_Event_Catalog" + '.xml', "QUAKEML") # ============================================================================= # ## 2. LOAD CATALOG IF AVAILABLE
def stalta_pick(stream, stalen, ltalen, trig_on, trig_off, freqmin=False, freqmax=False, show=False): """ Basic sta/lta picker, suggest using alternative in obspy. Simple sta/lta (short-term average/long-term average) picker, using obspy's :func:`obspy.signal.trigger.classic_sta_lta` routine to generate the characteristic function. Currently very basic quick wrapper, there are many other (better) options in obspy in the :mod:`obspy.signal.trigger` module. :type stream: obspy.core.stream.Stream :param stream: The stream to pick on, can be any number of channels. :type stalen: float :param stalen: Length of the short-term average window in seconds. :type ltalen: float :param ltalen: Length of the long-term average window in seconds. :type trig_on: float :param trig_on: sta/lta ratio to trigger a detection/pick :type trig_off: float :param trig_off: sta/lta ratio to turn the trigger off - no further picks\ will be made between exceeding trig_on until trig_off is reached. :type freqmin: float :param freqmin: Low-cut frequency in Hz for bandpass filter :type freqmax: float :param freqmax: High-cut frequency in Hz for bandpass filter :type show: bool :param show: Show picks on waveform. :returns: :class:`obspy.core.event.event.Event` .. rubric:: Example >>> from obspy import read >>> from eqcorrscan.utils.picker import stalta_pick >>> st = read() >>> event = stalta_pick(st, stalen=0.2, ltalen=4, trig_on=10, ... trig_off=1, freqmin=3.0, freqmax=20.0) >>> print(event.creation_info.author) EQcorrscan .. warning:: This function is not designed for accurate picking, rather it can give a first idea of whether picks may be possible. Proceed with caution. """ event = Event() event.origins.append(Origin()) event.creation_info = CreationInfo(author='EQcorrscan', creation_time=UTCDateTime()) event.comments.append(Comment(text='stalta')) picks = [] for tr in stream: # We are going to assume, for now, that if the pick is made on the # horizontal channel then it is an S, otherwise we will assume it is # a P-phase: obviously a bad assumption... if tr.stats.channel[-1] == 'Z': phase = 'P' else: phase = 'S' if freqmin and freqmax: tr.detrend('simple') tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax, corners=3, zerophase=True) df = tr.stats.sampling_rate cft = classic_sta_lta(tr.data, int(stalen * df), int(ltalen * df)) triggers = trigger_onset(cft, trig_on, trig_off) for trigger in triggers: on = tr.stats.starttime + (trigger[0] / df) # off = tr.stats.starttime + (trigger[1] / df) wav_id = WaveformStreamID(station_code=tr.stats.station, channel_code=tr.stats.channel, network_code=tr.stats.network) p = Pick(waveform_id=wav_id, phase_hint=phase, time=on) Logger.info('Pick made: {0}'.format(p)) picks.append(p) # QC picks pick_stations = list(set([pick.waveform_id.station_code for pick in picks])) for pick_station in pick_stations: station_picks = [ pick for pick in picks if pick.waveform_id.station_code == pick_station ] # If P-pick is after S-picks, remove it. p_time = [ pick.time for pick in station_picks if pick.phase_hint == 'P' ] s_time = [ pick.time for pick in station_picks if pick.phase_hint == 'S' ] if p_time > s_time: p_pick = [pick for pick in station_picks if pick.phase_hint == 'P'] for pick in p_pick: Logger.info('P pick after S pick, removing P pick') picks.remove(pick) event.picks = picks if show: plotting.pretty_template_plot(stream, event=event, title='Autopicks', size=(8, 9)) if len(event.picks) > 0: event.origins[0].time = min([pick.time for pick in event.picks]) - 1 # event.origins[0].latitude = float('nan') # event.origins[0].longitude = float('nan') # Set arbitrary origin time return event
def _dbs_associator(start_time, end_time, moving_window, tbl, pair_n, save_dir, station_list, consider_combination=False): if consider_combination == True: if platform.system() == 'Windows': Y2000_writer = open(save_dir + "\\" + "Y2000.phs", "w") else: Y2000_writer = open(save_dir + "/" + "Y2000.phs", "w") traceNmae_dic = dict() st = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S.%f') et = datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S.%f') total_t = et - st evid = 0 tt = st pbar = tqdm(total=int(np.ceil(total_t.total_seconds() / moving_window)), ncols=100) while tt < et: detections = tbl[(tbl.event_start_time >= tt) & ( tbl.event_start_time < tt + timedelta(seconds=moving_window))] pbar.update() if len(detections) >= pair_n: evid += 1 yr = "{:>4}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[0]) mo = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[1]) dy = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[2]) hr = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[0]) mi = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[1]) sec = "{:>4}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[2]) st_lat_DMS = _decimalDegrees2DMS( float(detections.iloc[0]['stlat']), "Latitude") st_lon_DMS = _decimalDegrees2DMS( float(detections.iloc[0]['stlon']), "Longitude") depth = 5.0 mag = 0.0 # QuakeML print(detections.iloc[0]['event_start_time']) if len(detections) / pair_n <= 2: ch = pair_n else: ch = int(len(detections) - pair_n) picks = [] for ns in range(ch, len(detections) + 1): comb = 0 for ind in list(combinations(detections.index, ns)): comb += 1 selected_detections = detections.loc[ind, :] sorted_detections = selected_detections.sort_values( 'p_arrival_time') Y2000_writer.write( "%4d%2d%2d%2d%2d%4.2f%2.0f%1s%4.2f%3.0f%1s%4.2f%5.2f%3.2f\n" % (int(yr), int(mo), int(dy), int(hr), int(mi), float(sec), float(st_lat_DMS[0]), str(st_lat_DMS[1]), float(st_lat_DMS[2]), float(st_lon_DMS[0]), str(st_lon_DMS[1]), float(st_lon_DMS[2]), float(depth), float(mag))) station_buffer = [] row_buffer = [] tr_names = [] tr_names2 = [] for _, row in sorted_detections.iterrows(): trace_name = row['traceID'] + '*' + row[ 'station'] + '*' + str(row['event_start_time']) p_unc = row['p_unc'] p_prob = row['p_prob'] s_unc = row['s_unc'] s_prob = row['s_prob'] if p_unc: Pweihgt = _weighcalculator_prob(p_prob * (1 - p_unc)) else: Pweihgt = _weighcalculator_prob(p_prob) try: Pweihgt = int(Pweihgt) except Exception: Pweihgt = 4 if s_unc: Sweihgt = _weighcalculator_prob(s_prob * (1 - s_unc)) else: Sweihgt = _weighcalculator_prob(s_prob) try: Sweihgt = int(Sweihgt) except Exception: Sweihgt = 4 station = "{:<5}".format(row['station']) network = "{:<2}".format(row['network']) try: yrp = "{:>4}".format( str(row['p_arrival_time']).split(' ') [0].split('-')[0]) mop = "{:>2}".format( str(row['p_arrival_time']).split(' ') [0].split('-')[1]) dyp = "{:>2}".format( str(row['p_arrival_time']).split(' ') [0].split('-')[2]) hrp = "{:>2}".format( str(row['p_arrival_time']).split(' ') [1].split(':')[0]) mip = "{:>2}".format( str(row['p_arrival_time']).split(' ') [1].split(':')[1]) sec_p = "{:>4}".format( str(row['p_arrival_time']).split(' ') [1].split(':')[2]) p = Pick(time=UTCDateTime( row['p_arrival_time']), waveform_id=WaveformStreamID( network_code=network, station_code=station.rstrip()), phase_hint="P") picks.append(p) except Exception: sec_p = None try: yrs = "{:>4}".format( str(row['s_arrival_time']).split(' ') [0].split('-')[0]) mos = "{:>2}".format( str(row['s_arrival_time']).split(' ') [0].split('-')[1]) dys = "{:>2}".format( str(row['s_arrival_time']).split(' ') [0].split('-')[2]) hrs = "{:>2}".format( str(row['s_arrival_time']).split(' ') [1].split(':')[0]) mis = "{:>2}".format( str(row['s_arrival_time']).split(' ') [1].split(':')[1]) sec_s = "{:>4}".format( str(row['s_arrival_time']).split(' ') [1].split(':')[2]) p = Pick(time=UTCDateTime( row['p_arrival_time']), waveform_id=WaveformStreamID( network_code=network, station_code=station.rstrip()), phase_hint="S") picks.append(p) except Exception: sec_s = None if row['station'] not in station_buffer: tr_names.append(trace_name) station_buffer.append(row['station']) if sec_s: Y2000_writer.write( "%5s%2s HHE %4d%2d%2d%2d%2d%5.2f %5.2fES %1d\n" % (station, network, int(yrs), int(mos), int(dys), int(hrs), int(mis), float(0.0), float(sec_s), Sweihgt)) if sec_p: Y2000_writer.write( "%5s%2s HHZ IP %1d%4d%2d%2d%2d%2d%5.2f %5.2f 0\n" % (station, network, Pweihgt, int(yrp), int(mop), int(dyp), int(hrp), int(mip), float(sec_p), float(0.0))) else: tr_names2.append(trace_name) if sec_s: row_buffer.append( "%5s%2s HHE %4d%2d%2d%2d%2d%5.2f %5.2fES %1d\n" % (station, network, int(yrs), int(mos), int(dys), int(hrs), int(mis), 0.0, float(sec_s), Sweihgt)) if sec_p: row_buffer.append( "%5s%2s HHZ IP %1d%4d%2d%2d%2d%2d%5.2f %5.2f 0\n" % (station, network, Pweihgt, int(yrp), int(mop), int(dyp), int(hrp), int(mip), float(sec_p), float(0.0))) Y2000_writer.write("{:<62}".format(' ') + "%10d" % (evid) + '\n') traceNmae_dic[str(evid)] = tr_names if len(row_buffer) >= 2 * pair_n: Y2000_writer.write( "%4d%2d%2d%2d%2d%4.2f%2.0f%1s%4.2f%3.0f%1s%4.2f%5.2f%3.2f\n" % (int(yr), int(mo), int(dy), int(hr), int(mi), float(sec), float(st_lat_DMS[0]), str( st_lat_DMS[1]), float(st_lat_DMS[2]), float(st_lon_DMS[0]), str(st_lon_DMS[1]), float(st_lon_DMS[2]), float(depth), float(mag))) for rr in row_buffer: Y2000_writer.write(rr) Y2000_writer.write("{:<62}".format(' ') + "%10d" % (evid) + '\n') traceNmae_dic[str(evid)] = tr_names2 tt += timedelta(seconds=moving_window) # plt.scatter(LTTP, TTP, s=10, marker='o', c='b', alpha=0.4, label='P') # plt.scatter(LTTS, TTS, s=10, marker='o', c='r', alpha=0.4, label='S') # plt.legend('upper right') # plt.show() print('The Number of Realizations: ' + str(evid) + '\n', flush=True) jj = json.dumps(traceNmae_dic) if platform.system() == 'Windows': f = open(save_dir + "\\" + "traceNmae_dic.json", "w") else: f = open(save_dir + "/" + "traceNmae_dic.json", "w") f.write(jj) f.close() else: if platform.system() == 'Windows': Y2000_writer = open(save_dir + "\\" + "Y2000.phs", "w") else: Y2000_writer = open(save_dir + "/" + "Y2000.phs", "w") cat = Catalog() traceNmae_dic = dict() st = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S.%f') et = datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S.%f') total_t = et - st evid = 200000 evidd = 100000 tt = st pbar = tqdm(total=int(np.ceil(total_t.total_seconds() / moving_window))) while tt < et: detections = tbl[(tbl.event_start_time >= tt) & ( tbl.event_start_time < tt + timedelta(seconds=moving_window))] pbar.update() if len(detections) >= pair_n: yr = "{:>4}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[0]) mo = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[1]) dy = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [0].split('-')[2]) hr = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[0]) mi = "{:>2}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[1]) sec = "{:>4}".format( str(detections.iloc[0]['event_start_time']).split(' ') [1].split(':')[2]) st_lat_DMS = _decimalDegrees2DMS( float(detections.iloc[0]['stlat']), "Latitude") st_lon_DMS = _decimalDegrees2DMS( float(detections.iloc[0]['stlon']), "Longitude") depth = 5.0 mag = 0.0 Y2000_writer.write( "%4d%2d%2d%2d%2d%4.2f%2.0f%1s%4.2f%3.0f%1s%4.2f%5.2f%3.2f\n" % (int(yr), int(mo), int(dy), int(hr), int(mi), float(sec), float(st_lat_DMS[0]), str(st_lat_DMS[1]), float(st_lat_DMS[2]), float(st_lon_DMS[0]), str(st_lon_DMS[1]), float( st_lon_DMS[2]), float(depth), float(mag))) event = Event() origin = Origin(time=UTCDateTime( detections.iloc[0]['event_start_time']), longitude=detections.iloc[0]['stlon'], latitude=detections.iloc[0]['stlat'], method="EqTransformer") event.origins.append(origin) station_buffer = [] row_buffer = [] sorted_detections = detections.sort_values('p_arrival_time') tr_names = [] tr_names2 = [] picks = [] for _, row in sorted_detections.iterrows(): trace_name = row['traceID'] + '*' + row[ 'station'] + '*' + str(row['event_start_time']) p_unc = row['p_unc'] p_prob = row['p_prob'] s_unc = row['s_unc'] s_prob = row['s_prob'] if p_unc: Pweihgt = _weighcalculator_prob(p_prob * (1 - p_unc)) else: Pweihgt = _weighcalculator_prob(p_prob) try: Pweihgt = int(Pweihgt) except Exception: Pweihgt = 4 if s_unc: Sweihgt = _weighcalculator_prob(s_prob * (1 - s_unc)) else: Sweihgt = _weighcalculator_prob(s_prob) try: Sweihgt = int(Sweihgt) except Exception: Sweihgt = 4 station = "{:<5}".format(row['station']) network = "{:<2}".format(row['network']) try: yrp = "{:>4}".format( str(row['p_arrival_time']).split(' ')[0].split('-') [0]) mop = "{:>2}".format( str(row['p_arrival_time']).split(' ')[0].split('-') [1]) dyp = "{:>2}".format( str(row['p_arrival_time']).split(' ')[0].split('-') [2]) hrp = "{:>2}".format( str(row['p_arrival_time']).split(' ')[1].split(':') [0]) mip = "{:>2}".format( str(row['p_arrival_time']).split(' ')[1].split(':') [1]) sec_p = "{:>4}".format( str(row['p_arrival_time']).split(' ')[1].split(':') [2]) p = Pick(time=UTCDateTime(row['p_arrival_time']), waveform_id=WaveformStreamID( network_code=network, station_code=station.rstrip()), phase_hint="P", method_id="EqTransformer") picks.append(p) except Exception: sec_p = None try: yrs = "{:>4}".format( str(row['s_arrival_time']).split(' ')[0].split('-') [0]) mos = "{:>2}".format( str(row['s_arrival_time']).split(' ')[0].split('-') [1]) dys = "{:>2}".format( str(row['s_arrival_time']).split(' ')[0].split('-') [2]) hrs = "{:>2}".format( str(row['s_arrival_time']).split(' ')[1].split(':') [0]) mis = "{:>2}".format( str(row['s_arrival_time']).split(' ')[1].split(':') [1]) sec_s = "{:>4}".format( str(row['s_arrival_time']).split(' ')[1].split(':') [2]) p = Pick(time=UTCDateTime(row['s_arrival_time']), waveform_id=WaveformStreamID( network_code=network, station_code=station.rstrip()), phase_hint="S", method_id="EqTransformer") picks.append(p) except Exception: sec_s = None if row['station'] not in station_buffer: tr_names.append(trace_name) station_buffer.append(row['station']) if sec_s: Y2000_writer.write( "%5s%2s HHE %4d%2d%2d%2d%2d%5.2f %5.2fES %1d\n" % (station, network, int(yrs), int(mos), int(dys), int(hrs), int(mis), float(0.0), float(sec_s), Sweihgt)) if sec_p: Y2000_writer.write( "%5s%2s HHZ IP %1d%4d%2d%2d%2d%2d%5.2f %5.2f 0\n" % (station, network, Pweihgt, int(yrp), int(mop), int(dyp), int(hrp), int(mip), float(sec_p), float(0.0))) else: tr_names2.append(trace_name) if sec_s: row_buffer.append( "%5s%2s HHE %4d%2d%2d%2d%2d%5.2f %5.2fES %1d\n" % (station, network, int(yrs), int(mos), int(dys), int(hrs), int(mis), 0.0, float(sec_s), Sweihgt)) if sec_p: row_buffer.append( "%5s%2s HHZ IP %1d%4d%2d%2d%2d%2d%5.2f %5.2f 0\n" % (station, network, Pweihgt, int(yrp), int(mop), int(dyp), int(hrp), int(mip), float(sec_p), float(0.0))) event.picks = picks event.preferred_origin_id = event.origins[0].resource_id cat.append(event) evid += 1 Y2000_writer.write("{:<62}".format(' ') + "%10d" % (evid) + '\n') traceNmae_dic[str(evid)] = tr_names if len(row_buffer) >= 2 * pair_n: Y2000_writer.write( "%4d%2d%2d%2d%2d%4.2f%2.0f%1s%4.2f%3.0f%1s%4.2f%5.2f%3.2f\n" % (int(yr), int(mo), int(dy), int(hr), int(mi), float(sec), float(st_lat_DMS[0]), str( st_lat_DMS[1]), float(st_lat_DMS[2]), float(st_lon_DMS[0]), str(st_lon_DMS[1]), float(st_lon_DMS[2]), float(depth), float(mag))) for rr in row_buffer: Y2000_writer.write(rr) evid += 1 Y2000_writer.write("{:<62}".format(' ') + "%10d" % (evid) + '\n') traceNmae_dic[str(evid)] = tr_names2 elif len(row_buffer) < pair_n and len(row_buffer) != 0: evidd += 1 traceNmae_dic[str(evidd)] = tr_names2 elif len(detections) < pair_n and len(detections) != 0: tr_names = [] for _, row in detections.iterrows(): trace_name = row['traceID'] tr_names.append(trace_name) evidd += 1 traceNmae_dic[str(evidd)] = tr_names tt += timedelta(seconds=moving_window) print('The Number of Associated Events: ' + str(evid - 200000) + '\n', flush=True) jj = json.dumps(traceNmae_dic) if platform.system() == 'Windows': f = open(save_dir + "\\" + "traceNmae_dic.json", "w") else: f = open(save_dir + "/" + "traceNmae_dic.json", "w") f.write(jj) f.close() print(cat.__str__(print_all=True)) cat.write(save_dir + "/associations.xml", format="QUAKEML")
def full_test_event(): """ Function to generate a basic, full test event """ test_event = Event() test_event.origins.append(Origin()) test_event.origins[0].time = UTCDateTime("2012-03-26") + 1.2 test_event.event_descriptions.append(EventDescription()) test_event.event_descriptions[0].text = 'LE' test_event.origins[0].latitude = 45.0 test_event.origins[0].longitude = 25.0 test_event.origins[0].depth = 15000 test_event.creation_info = CreationInfo(agency_id='TES') test_event.origins[0].quality = OriginQuality(standard_error=0.01) test_event.magnitudes.append(Magnitude()) test_event.magnitudes[0].mag = 0.1 test_event.magnitudes[0].magnitude_type = 'ML' test_event.magnitudes[0].creation_info = CreationInfo('TES') test_event.magnitudes[0].origin_id = test_event.origins[0].resource_id test_event.magnitudes.append(Magnitude()) test_event.magnitudes[1].mag = 0.5 test_event.magnitudes[1].magnitude_type = 'Mc' test_event.magnitudes[1].creation_info = CreationInfo('TES') test_event.magnitudes[1].origin_id = test_event.origins[0].resource_id test_event.magnitudes.append(Magnitude()) test_event.magnitudes[2].mag = 1.3 test_event.magnitudes[2].magnitude_type = 'Ms' test_event.magnitudes[2].creation_info = CreationInfo('TES') test_event.magnitudes[2].origin_id = test_event.origins[0].resource_id # Define the test pick _waveform_id_1 = WaveformStreamID(station_code='FOZ', channel_code='SHZ', network_code='NZ') _waveform_id_2 = WaveformStreamID(station_code='WTSZ', channel_code='BH1', network_code=' ') # Pick to associate with amplitude - 0 test_event.picks = [ Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, onset='impulsive', phase_hint='PN', polarity='positive', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='SG', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.72, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='PN', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.62, evaluation_mode="automatic")] # Test a generic local magnitude amplitude pick test_event.amplitudes = [ Amplitude(generic_amplitude=2.0, period=0.4, pick_id=test_event.picks[0].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', magnitude_hint='ML', category='point', type='AML'), Amplitude(generic_amplitude=10, pick_id=test_event.picks[1].resource_id, waveform_id=test_event.picks[1].waveform_id, type='END', category='duration', unit='s', magnitude_hint='Mc', snr=2.3), Amplitude(generic_amplitude=5.0, period=0.6, pick_id=test_event.picks[2].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', category='point', type='AML')] test_event.origins[0].arrivals = [ Arrival(time_weight=0, phase=test_event.picks[1].phase_hint, pick_id=test_event.picks[1].resource_id), Arrival(time_weight=2, phase=test_event.picks[3].phase_hint, pick_id=test_event.picks[3].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25), Arrival(time_weight=2, phase=test_event.picks[4].phase_hint, pick_id=test_event.picks[4].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25)] return test_event
def full_test_event(): """ Function to generate a basic, full test event """ test_event = Event() test_event.origins.append(Origin( time=UTCDateTime("2012-03-26") + 1.2, latitude=45.0, longitude=25.0, depth=15000)) test_event.event_descriptions.append(EventDescription()) test_event.event_descriptions[0].text = 'LE' test_event.creation_info = CreationInfo(agency_id='TES') test_event.magnitudes.append(Magnitude( mag=0.1, magnitude_type='ML', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) test_event.magnitudes.append(Magnitude( mag=0.5, magnitude_type='Mc', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) test_event.magnitudes.append(Magnitude( mag=1.3, magnitude_type='Ms', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) # Define the test pick _waveform_id_1 = WaveformStreamID(station_code='FOZ', channel_code='SHZ', network_code='NZ') _waveform_id_2 = WaveformStreamID(station_code='WTSZ', channel_code='BH1', network_code=' ') # Pick to associate with amplitude - 0 test_event.picks = [ Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, onset='impulsive', phase_hint='PN', polarity='positive', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='SG', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.72, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='PN', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.62, evaluation_mode="automatic")] # Test a generic local magnitude amplitude pick test_event.amplitudes = [ Amplitude(generic_amplitude=2.0, period=0.4, pick_id=test_event.picks[0].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', magnitude_hint='ML', category='point', type='AML'), Amplitude(generic_amplitude=10, pick_id=test_event.picks[1].resource_id, waveform_id=test_event.picks[1].waveform_id, type='END', category='duration', unit='s', magnitude_hint='Mc', snr=2.3), Amplitude(generic_amplitude=5.0, period=0.6, pick_id=test_event.picks[2].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', category='point', type='AML')] test_event.origins[0].arrivals = [ Arrival(time_weight=0, phase=test_event.picks[1].phase_hint, pick_id=test_event.picks[1].resource_id), Arrival(time_weight=2, phase=test_event.picks[3].phase_hint, pick_id=test_event.picks[3].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25), Arrival(time_weight=2, phase=test_event.picks[4].phase_hint, pick_id=test_event.picks[4].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25)] # Add in error info (line E) test_event.origins[0].quality = OriginQuality( standard_error=0.01, azimuthal_gap=36) # Origin uncertainty in Seisan is output as long-lat-depth, quakeML has # semi-major and semi-minor test_event.origins[0].origin_uncertainty = OriginUncertainty( confidence_ellipsoid=ConfidenceEllipsoid( semi_major_axis_length=3000, semi_minor_axis_length=1000, semi_intermediate_axis_length=2000, major_axis_plunge=20, major_axis_azimuth=100, major_axis_rotation=4)) test_event.origins[0].time_errors = QuantityError(uncertainty=0.5) # Add in fault-plane solution info (line F) - Note have to check program # used to determine which fields are filled.... test_event.focal_mechanisms.append(FocalMechanism( nodal_planes=NodalPlanes(nodal_plane_1=NodalPlane( strike=180, dip=20, rake=30, strike_errors=QuantityError(10), dip_errors=QuantityError(10), rake_errors=QuantityError(20))), method_id=ResourceIdentifier("smi:nc.anss.org/focalMechanism/FPFIT"), creation_info=CreationInfo(agency_id="NC"), misfit=0.5, station_distribution_ratio=0.8)) # Need to test high-precision origin and that it is preferred origin. # Moment tensor includes another origin test_event.origins.append(Origin( time=UTCDateTime("2012-03-26") + 1.2, latitude=45.1, longitude=25.2, depth=14500)) test_event.magnitudes.append(Magnitude( mag=0.1, magnitude_type='MW', creation_info=CreationInfo('TES'), origin_id=test_event.origins[-1].resource_id)) # Moment tensors go with focal-mechanisms test_event.focal_mechanisms.append(FocalMechanism( moment_tensor=MomentTensor( derived_origin_id=test_event.origins[-1].resource_id, moment_magnitude_id=test_event.magnitudes[-1].resource_id, scalar_moment=100, tensor=Tensor( m_rr=100, m_tt=100, m_pp=10, m_rt=1, m_rp=20, m_tp=15), method_id=ResourceIdentifier( 'smi:nc.anss.org/momentTensor/BLAH')))) return test_event
def outputOBSPY(hp, event=None, only_fm_picks=False): """ Make an Event which includes the current focal mechanism information from HASH Use the 'only_fm_picks' flag to only include the picks HASH used for the FocalMechanism. This flag will replace the 'picks' and 'arrivals' lists of existing events with new ones. Inputs ------- hp : hashpy.HashPype instance event : obspy.core.event.Event only_fm_picks : bool of whether to overwrite the picks/arrivals lists Returns ------- obspy.core.event.Event Event will be new if no event was input, FocalMech added to existing event """ # Returns new (or updates existing) Event with HASH solution n = hp.npol if event is None: event = Event(focal_mechanisms=[], picks=[], origins=[]) origin = Origin(arrivals=[]) origin.time = UTCDateTime(hp.tstamp) origin.latitude = hp.qlat origin.longitude = hp.qlon origin.depth = hp.qdep origin.creation_info = CreationInfo(version=hp.icusp) origin.resource_id = ResourceIdentifier('smi:hash/Origin/{0}'.format( hp.icusp)) for _i in range(n): p = Pick() p.creation_info = CreationInfo(version=hp.arid[_i]) p.resource_id = ResourceIdentifier('smi:nsl/Pick/{0}'.format( p.creation_info.version)) p.waveform_id = WaveformStreamID(network_code=hp.snet[_i], station_code=hp.sname[_i], channel_code=hp.scomp[_i]) if hp.p_pol[_i] > 0: p.polarity = 'positive' else: p.polarity = 'negative' a = Arrival() a.creation_info = CreationInfo(version=hp.arid[_i]) a.resource_id = ResourceIdentifier('smi:nsl/Arrival/{0}'.format( p.creation_info.version)) a.azimuth = hp.p_azi_mc[_i, 0] a.takeoff_angle = 180. - hp.p_the_mc[_i, 0] a.pick_id = p.resource_id origin.arrivals.append(a) event.picks.append(p) event.origins.append(origin) event.preferred_origin_id = origin.resource_id.resource_id else: # just update the changes origin = event.preferred_origin() picks = [] arrivals = [] for _i in range(n): ind = hp.p_index[_i] a = origin.arrivals[ind] p = a.pick_id.getReferredObject() a.takeoff_angle = hp.p_the_mc[_i, 0] picks.append(p) arrivals.append(a) if only_fm_picks: origin.arrivals = arrivals event.picks = picks # Use me double couple calculator and populate planes/axes etc x = hp._best_quality_index # Put all the mechanisms into the 'focal_mechanisms' list, mark "best" as preferred for s in range(hp.nmult): dc = DoubleCouple([hp.str_avg[s], hp.dip_avg[s], hp.rak_avg[s]]) ax = dc.axis focal_mech = FocalMechanism() focal_mech.creation_info = CreationInfo(creation_time=UTCDateTime(), author=hp.author) focal_mech.triggering_origin_id = origin.resource_id focal_mech.resource_id = ResourceIdentifier( 'smi:hash/FocalMechanism/{0}/{1}'.format(hp.icusp, s + 1)) focal_mech.method_id = ResourceIdentifier('HASH') focal_mech.nodal_planes = NodalPlanes() focal_mech.nodal_planes.nodal_plane_1 = NodalPlane(*dc.plane1) focal_mech.nodal_planes.nodal_plane_2 = NodalPlane(*dc.plane2) focal_mech.principal_axes = PrincipalAxes() focal_mech.principal_axes.t_axis = Axis(azimuth=ax['T']['azimuth'], plunge=ax['T']['dip']) focal_mech.principal_axes.p_axis = Axis(azimuth=ax['P']['azimuth'], plunge=ax['P']['dip']) focal_mech.station_polarity_count = n focal_mech.azimuthal_gap = hp.magap focal_mech.misfit = hp.mfrac[s] focal_mech.station_distribution_ratio = hp.stdr[s] focal_mech.comments.append( Comment( hp.qual[s], resource_id=ResourceIdentifier( focal_mech.resource_id.resource_id + '/comment/quality'))) #---------------------------------------- event.focal_mechanisms.append(focal_mech) if s == x: event.preferred_focal_mechanism_id = focal_mech.resource_id.resource_id return event
def stalta_pick(stream, stalen, ltalen, trig_on, trig_off, freqmin=False, freqmax=False, debug=0, show=False): """ Basic sta/lta picker, suggest using alternative in obspy. Simple sta-lta (short-term average/long-term average) picker, using \ obspy's stalta routine to generate the characteristic function. Currently very basic quick wrapper, there are many other (better) options \ in obspy, found \ `here <http://docs.obspy.org/packages/autogen/obspy.signal.trigger.html>`_. :type stream: obspy.Stream :param stream: The stream to pick on, can be any number of channels. :type stalen: float :param stalen: Length of the short-term average window in seconds. :type ltalen: float :param ltalen: Length of the long-term average window in seconds. :type trig_on: float :param trig_on: sta/lta ratio to trigger a detection/pick :type trig_off: float :param trig_off: sta/lta ratio to turn the trigger off - no further picks\ will be made between exceeding trig_on until trig_off is reached. :type freqmin: float :param freqmin: Low-cut frequency in Hz for bandpass filter :type freqmax: float :param freqmax: High-cut frequency in Hz for bandpass filter :type debug: int :param debug: Debug output level from 0-5. :type show: bool :param show: Show picks on waveform. :returns: obspy.core.event.Event .. rubric:: Example >>> from obspy import read >>> from eqcorrscan.utils.picker import stalta_pick >>> st = read() >>> event = stalta_pick(st, stalen=0.2, ltalen=4, trig_on=10, ... trig_off=1, freqmin=3.0, freqmax=20.0) >>> event.creation_info.author 'EQcorrscan' """ from obspy.signal.trigger import classic_sta_lta, trigger_onset from obspy.signal.trigger import plot_trigger from obspy import UTCDateTime from obspy.core.event import Event, Pick, WaveformStreamID from obspy.core.event import CreationInfo, Comment, Origin import eqcorrscan.utils.plotting as plotting event = Event() event.origins.append(Origin()) event.creation_info = CreationInfo(author='EQcorrscan', creation_time=UTCDateTime()) event.comments.append(Comment(text='stalta')) picks = [] for tr in stream: # We are going to assume, for now, that if the pick is made on the # horizontal channel then it is an S, otherwise we will assume it is # a P-phase: obviously a bad assumption... if tr.stats.channel[-1] == 'Z': phase = 'P' else: phase = 'S' if freqmin and freqmax: tr.detrend('simple') tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax, corners=3, zerophase=True) df = tr.stats.sampling_rate cft = classic_sta_lta(tr.data, int(stalen * df), int(ltalen * df)) if debug > 3: plot_trigger(tr, cft, trig_on, trig_off) triggers = trigger_onset(cft, trig_on, trig_off) for trigger in triggers: on = tr.stats.starttime + (trigger[0] / df) # off = tr.stats.starttime + (trigger[1] / df) wav_id = WaveformStreamID(station_code=tr.stats.station, channel_code=tr.stats.channel, network_code=tr.stats.network) pick = Pick(waveform_id=wav_id, phase_hint=phase, time=on) if debug > 2: print('Pick made:') print(pick) picks.append(pick) # QC picks del pick pick_stations = list(set([pick.waveform_id.station_code for pick in picks])) for pick_station in pick_stations: station_picks = [ pick for pick in picks if pick.waveform_id.station_code == pick_station ] # If P-pick is after S-picks, remove it. p_time = [ pick.time for pick in station_picks if pick.phase_hint == 'P' ] s_time = [ pick.time for pick in station_picks if pick.phase_hint == 'S' ] if p_time > s_time: p_pick = [pick for pick in station_picks if pick.phase_hint == 'P'] for pick in p_pick: print('P pick after S pick, removing P pick') picks.remove(pick) if show: plotting.pretty_template_plot(stream, picks=picks, title='Autopicks', size=(8, 9)) event.picks = picks event.origins[0].time = min([pick.time for pick in event.picks]) - 1 event.origins[0].latitude = float('nan') event.origins[0].longitude = float('nan') # Set arbitrary origin time return event
def plot_detection(grid, receivers, frames, tmin_frames, deltat_cf, imax, iframe, xpeak, ypeak, zpeak, tr_stackmax, tpeaks, apeaks, detector_threshold, wmin, wmax, pdata, trs_raw, fmin, fmax, idetection, tpeaksearch, movie=False, save_filename=None, show=True, event=None): from matplotlib import pyplot as plt from matplotlib import cm from matplotlib.animation import FuncAnimation nsls = set(tr.nslc_id[:3] for tr in trs_raw) receivers_on = [r for r in receivers if r.codes in nsls] receivers_off = [r for r in receivers if r.codes not in nsls] distances = grid.distances(receivers) plot.mpl_init(fontsize=9) fig = plt.figure(figsize=plot.mpl_papersize('a4', 'landscape')) axes = plt.subplot2grid((2, 3), (0, 2), aspect=1.0) plot.mpl_labelspace(axes) axes2 = plt.subplot2grid((2, 3), (1, 2)) plot.mpl_labelspace(axes2) axes3 = plt.subplot2grid((2, 3), (0, 1), rowspan=2) axes4 = plt.subplot2grid((2, 3), (0, 0), rowspan=2) if grid.distance_max() > km: dist_units = km axes.set_xlabel('Easting [km]') axes.set_ylabel('Northing [km]') axes4.set_ylabel('Distance [km]') else: dist_units = 1.0 axes.set_xlabel('Easting [m]') axes.set_ylabel('Northing [m]') axes4.set_ylabel('Distance [m]') axes.locator_params(nbins=6, tight=True) axes2.set_xlabel('Time [s]') axes2.set_ylabel('Detector level') axes3.set_xlabel('Time [s]') for el in axes3.get_yticklabels(): el.set_visible(False) axes4.set_xlabel('Time [s]') tpeak_current = tmin_frames + deltat_cf * iframe t0 = tpeak_current tduration = 2.0 * tpeaksearch axes2.axvspan(tr_stackmax.tmin - t0, wmin - t0, color=plot.mpl_color('aluminium2')) axes2.axvspan(wmax - t0, tr_stackmax.tmax - t0, color=plot.mpl_color('aluminium2')) axes2.axvspan(tpeak_current - 0.5 * tduration - t0, tpeak_current + 0.5 * tduration - t0, color=plot.mpl_color('scarletred2'), alpha=0.3, lw=0.) axes2.set_xlim(tr_stackmax.tmin - t0, tr_stackmax.tmax - t0) axes2.axhline(detector_threshold, color=plot.mpl_color('aluminium6'), lw=2.) t = tr_stackmax.get_xdata() amp = tr_stackmax.get_ydata() axes2.plot(t - t0, amp, color=plot.mpl_color('scarletred2'), lw=1.) for tpeak, apeak in zip(tpeaks, apeaks): axes2.plot(tpeak - t0, apeak, '*', ms=20., mfc='white', mec='black') station_index = dict((rec.codes, i) for (i, rec) in enumerate(receivers)) dists_all = [] amps = [] shifts = [] pdata2 = [] for trs, shift_table, shifter in pdata: trs = [tr.copy() for tr in trs] dists = [] for tr in trs: istation = station_index[tr.nslc_id[:3]] shift = shift_table[imax, istation] tr2 = tr.chop(tpeak_current - 0.5 * tduration + shift, tpeak_current + 0.5 * tduration + shift, inplace=False) dists.append(distances[imax, istation]) amp = tr2.get_ydata() * shifter.weight amps.append(num.max(num.abs(amp))) shifts.append(shift) pdata2.append((trs, dists, shift_table, shifter)) dists_all.extend(dists) dist_min = min(dists_all) dist_max = max(dists_all) shift_min = min(shifts) shift_max = max(shifts) amp_max = max(amps) scalefactor = (dist_max - dist_min) / len(trs) * 0.5 axes3.set_xlim(-0.5 * tduration + shift_min, 0.5 * tduration + shift_max) axes3.set_ylim((dist_min - scalefactor) / dist_units, (dist_max + scalefactor) / dist_units) axes4.set_xlim(-0.5 * tduration + shift_min, 0.5 * tduration + shift_max) axes4.set_ylim((dist_min - scalefactor) / dist_units, (dist_max + scalefactor) / dist_units) axes3.axvline(0., color=plot.mpl_color('aluminium3'), lw=2.) nsl_have = set() phase_markers = [] picks = [] for ishifter, (trs, dists, shift_table, shifter) in enumerate(pdata2): color = plot.mpl_graph_color(ishifter) for tr, dist in zip(trs, dists): tmint = tr.tmin tr = tr.chop(tpeak_current - 0.5 * tduration + shift_min, tpeak_current + 0.5 * tduration + shift_max, inplace=False) nsl = tr.nslc_id[:3] istation = station_index[nsl] shift = shift_table[imax, istation] phase_markers.append( PhaseMarker([(nsl[0], nsl[1], "", nsl[2])], tmin=tmint + shift, tmax=tmint + shift, phasename=shifter.name, event_time=t0, event_hash=idetection)) p = Pick(time=UTCDateTime(tmint + shift), waveform_id=WaveformStreamID(network_code=nsl[0], station_code=nsl[1]), phase_hint=shifter.name, method_id="lassie") picks.append(p) axes3.plot(shift, dist / dist_units, '|', mew=2, mec=color, ms=10, zorder=2) t = tr.get_xdata() amp = tr.get_ydata() * shifter.weight amp /= amp_max axes3.plot( t - t0, (dist + scalefactor * amp + ishifter * scalefactor * 0.1) / dist_units, color=color, zorder=1) if nsl not in nsl_have: axes3.annotate('.'.join(nsl), xy=(t[0] - t0, dist / dist_units), xytext=(10., 0.), textcoords='offset points', verticalalignment='top') nsl_have.add(nsl) for tr in trs_raw: istation = station_index[tr.nslc_id[:3]] dist = distances[imax, istation] shift = shift_table[imax, istation] tr = tr.copy() tr.highpass(4, fmin, demean=True) tr.lowpass(4, fmax, demean=False) tr.chop(tpeak_current - 0.5 * tduration + shift_min, tpeak_current + 0.5 * tduration + shift_max) t = tr.get_xdata() amp = tr.get_ydata().astype(num.float) amp = amp / num.max(num.abs(amp)) axes4.plot(t - t0, (dist + scalefactor * amp) / dist_units, color='black', alpha=0.5, zorder=1) axes4.plot(shift, dist / dist_units, '|', mew=2, mec=color, ms=10, zorder=2) PhaseMarker.save_markers(phase_markers, "%s.pym" % (save_filename[:-4]), fdigits=3) event_obspy = Event() origin = Origin(time=UTCDateTime(t0), longitude=event.lon, latitude=event.lat, method="lassie") event_obspy.origins.append(origin) event_obspy.picks = picks cat = Catalog() cat.append(event_obspy) cat.write(save_filename[:-4] + ".qml", format="QUAKEML") nframes = frames.shape[1] iframe_min = max(0, int(round(iframe - 0.5 * tduration / deltat_cf))) iframe_max = min(nframes - 1, int(round(iframe + 0.5 * tduration / deltat_cf))) amax = frames[imax, iframe] axes.set_xlim(grid.ymin / dist_units, grid.ymax / dist_units) axes.set_ylim(grid.xmin / dist_units, grid.xmax / dist_units) cmap = cm.YlOrBr system = ('ne', grid.lat, grid.lon) static_artists = [] static_artists.extend( plot_receivers(axes, receivers_on, system=system, units=dist_units, style=dict(mfc='black', ms=5.0))) static_artists.extend( plot_receivers(axes, receivers_off, system=system, units=dist_units, style=dict(mfc='none', ms=5.0))) static_artists.extend( axes.plot(ypeak / dist_units, xpeak / dist_units, '*', ms=20., mec='black', mfc='white')) static_artists.append( fig.suptitle('%06i - %s' % (idetection, util.time_to_str(t0)))) frame_artists = [] progress_artists = [] def update(iframe): if iframe is not None: frame = frames[:, iframe] if not progress_artists: progress_artists[:] = [ axes2.axvline(tmin_frames - t0 + deltat_cf * iframe, color=plot.mpl_color('scarletred3'), alpha=0.5, lw=2.) ] else: progress_artists[0].set_xdata(tmin_frames - t0 + deltat_cf * iframe) else: frame = num.max(frames[:, iframe_min:iframe_max + 1], axis=1) frame_artists[:] = grid.plot(axes, frame, amin=0.0, amax=amax, cmap=cmap, system=system, artists=frame_artists, units=dist_units, shading='gouraud') return frame_artists + progress_artists + static_artists if movie: ani = FuncAnimation( fig, update, frames=list(range(iframe_min, iframe_max + 1))[::10] + [None], interval=20., repeat=False, blit=True) else: ani = None update(None) if save_filename: fig.savefig(save_filename) if show: plt.show() else: plt.close() del ani
def outputOBSPY(hp, event=None, only_fm_picks=False): """ Make an Event which includes the current focal mechanism information from HASH Use the 'only_fm_picks' flag to only include the picks HASH used for the FocalMechanism. This flag will replace the 'picks' and 'arrivals' lists of existing events with new ones. Inputs ------- hp : hashpy.HashPype instance event : obspy.core.event.Event only_fm_picks : bool of whether to overwrite the picks/arrivals lists Returns ------- obspy.core.event.Event Event will be new if no event was input, FocalMech added to existing event """ # Returns new (or updates existing) Event with HASH solution n = hp.npol if event is None: event = Event(focal_mechanisms=[], picks=[], origins=[]) origin = Origin(arrivals=[]) origin.time = UTCDateTime(hp.tstamp) origin.latitude = hp.qlat origin.longitude = hp.qlon origin.depth = hp.qdep origin.creation_info = CreationInfo(version=hp.icusp) origin.resource_id = ResourceIdentifier('smi:hash/Origin/{0}'.format(hp.icusp)) for _i in range(n): p = Pick() p.creation_info = CreationInfo(version=hp.arid[_i]) p.resource_id = ResourceIdentifier('smi:hash/Pick/{0}'.format(p.creation_info.version)) p.waveform_id = WaveformStreamID(network_code=hp.snet[_i], station_code=hp.sname[_i], channel_code=hp.scomp[_i]) if hp.p_pol[_i] > 0: p.polarity = 'positive' else: p.polarity = 'negative' a = Arrival() a.creation_info = CreationInfo(version=hp.arid[_i]) a.resource_id = ResourceIdentifier('smi:hash/Arrival/{0}'.format(p.creation_info.version)) a.azimuth = hp.p_azi_mc[_i,0] a.takeoff_angle = 180. - hp.p_the_mc[_i,0] a.pick_id = p.resource_id origin.arrivals.append(a) event.picks.append(p) event.origins.append(origin) event.preferred_origin_id = str(origin.resource_id) else: # just update the changes origin = event.preferred_origin() picks = [] arrivals = [] for _i in range(n): ind = hp.p_index[_i] a = origin.arrivals[ind] p = a.pick_id.getReferredObject() a.takeoff_angle = hp.p_the_mc[_i,0] picks.append(p) arrivals.append(a) if only_fm_picks: origin.arrivals = arrivals event.picks = picks # Use me double couple calculator and populate planes/axes etc x = hp._best_quality_index # Put all the mechanisms into the 'focal_mechanisms' list, mark "best" as preferred for s in range(hp.nmult): dc = DoubleCouple([hp.str_avg[s], hp.dip_avg[s], hp.rak_avg[s]]) ax = dc.axis focal_mech = FocalMechanism() focal_mech.creation_info = CreationInfo(creation_time=UTCDateTime(), author=hp.author) focal_mech.triggering_origin_id = origin.resource_id focal_mech.resource_id = ResourceIdentifier('smi:hash/FocalMechanism/{0}/{1}'.format(hp.icusp, s+1)) focal_mech.method_id = ResourceIdentifier('HASH') focal_mech.nodal_planes = NodalPlanes() focal_mech.nodal_planes.nodal_plane_1 = NodalPlane(*dc.plane1) focal_mech.nodal_planes.nodal_plane_2 = NodalPlane(*dc.plane2) focal_mech.principal_axes = PrincipalAxes() focal_mech.principal_axes.t_axis = Axis(azimuth=ax['T']['azimuth'], plunge=ax['T']['dip']) focal_mech.principal_axes.p_axis = Axis(azimuth=ax['P']['azimuth'], plunge=ax['P']['dip']) focal_mech.station_polarity_count = n focal_mech.azimuthal_gap = hp.magap focal_mech.misfit = hp.mfrac[s] focal_mech.station_distribution_ratio = hp.stdr[s] focal_mech.comments.append( Comment(hp.qual[s], resource_id=ResourceIdentifier(str(focal_mech.resource_id) + '/comment/quality')) ) #---------------------------------------- event.focal_mechanisms.append(focal_mech) if s == x: event.preferred_focal_mechanism_id = str(focal_mech.resource_id) return event
def stalta_pick(stream, stalen, ltalen, trig_on, trig_off, freqmin=False, freqmax=False, debug=0, show=False): """ Basic sta/lta picker, suggest using alternative in obspy. Simple sta-lta (short-term average/long-term average) picker, using \ obspy's stalta routine to generate the characteristic function. Currently very basic quick wrapper, there are many other (better) options \ in obspy, found \ `here <http://docs.obspy.org/packages/autogen/obspy.signal.trigger.html>`_. :type stream: obspy.Stream :param stream: The stream to pick on, can be any number of channels. :type stalen: float :param stalen: Length of the short-term average window in seconds. :type ltalen: float :param ltalen: Length of the long-term average window in seconds. :type trig_on: float :param trig_on: sta/lta ratio to trigger a detection/pick :type trig_off: float :param trig_off: sta/lta ratio to turn the trigger off - no further picks\ will be made between exceeding trig_on until trig_off is reached. :type freqmin: float :param freqmin: Low-cut frequency in Hz for bandpass filter :type freqmax: float :param freqmax: High-cut frequency in Hz for bandpass filter :type debug: int :param debug: Debug output level from 0-5. :type show: bool :param show: Show picks on waveform. :returns: obspy.core.event.Event .. rubric:: Example >>> from obspy import read >>> from eqcorrscan.utils.picker import stalta_pick >>> st = read() >>> event = stalta_pick(st, stalen=0.2, ltalen=4, trig_on=10, ... trig_off=1, freqmin=3.0, freqmax=20.0) >>> event.creation_info.author 'EQcorrscan' """ from obspy.signal.trigger import classic_sta_lta, trigger_onset from obspy.signal.trigger import plot_trigger from obspy import UTCDateTime from obspy.core.event import Event, Pick, WaveformStreamID from obspy.core.event import CreationInfo, Comment, Origin import eqcorrscan.utils.plotting as plotting event = Event() event.origins.append(Origin()) event.creation_info = CreationInfo(author='EQcorrscan', creation_time=UTCDateTime()) event.comments.append(Comment(text='stalta')) picks = [] for tr in stream: # We are going to assume, for now, that if the pick is made on the # horizontal channel then it is an S, otherwise we will assume it is # a P-phase: obviously a bad assumption... if tr.stats.channel[-1] == 'Z': phase = 'P' else: phase = 'S' if freqmin and freqmax: tr.detrend('simple') tr.filter('bandpass', freqmin=freqmin, freqmax=freqmax, corners=3, zerophase=True) df = tr.stats.sampling_rate cft = classic_sta_lta(tr.data, int(stalen * df), int(ltalen * df)) if debug > 3: plot_trigger(tr, cft, trig_on, trig_off) triggers = trigger_onset(cft, trig_on, trig_off) for trigger in triggers: on = tr.stats.starttime + (trigger[0] / df) # off = tr.stats.starttime + (trigger[1] / df) wav_id = WaveformStreamID(station_code=tr.stats.station, channel_code=tr.stats.channel, network_code=tr.stats.network) pick = Pick(waveform_id=wav_id, phase_hint=phase, time=on) if debug > 2: print('Pick made:') print(pick) picks.append(pick) # QC picks del pick pick_stations = list(set([pick.waveform_id.station_code for pick in picks])) for pick_station in pick_stations: station_picks = [pick for pick in picks if pick.waveform_id.station_code == pick_station] # If P-pick is after S-picks, remove it. p_time = [pick.time for pick in station_picks if pick.phase_hint == 'P'] s_time = [pick.time for pick in station_picks if pick.phase_hint == 'S'] if p_time > s_time: p_pick = [pick for pick in station_picks if pick.phase_hint == 'P'] for pick in p_pick: print('P pick after S pick, removing P pick') picks.remove(pick) if show: plotting.pretty_template_plot(stream, picks=picks, title='Autopicks', size=(8, 9)) event.picks = picks event.origins[0].time = min([pick.time for pick in event.picks]) - 1 event.origins[0].latitude = float('nan') event.origins[0].longitude = float('nan') # Set arbitrary origin time return event
def full_test_event(): """ Function to generate a basic, full test event """ test_event = Event() test_event.origins.append( Origin(time=UTCDateTime("2012-03-26") + 1.2, latitude=45.0, longitude=25.0, depth=15000)) test_event.event_descriptions.append(EventDescription()) test_event.event_descriptions[0].text = 'LE' test_event.creation_info = CreationInfo(agency_id='TES') test_event.magnitudes.append( Magnitude(mag=0.1, magnitude_type='ML', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) test_event.magnitudes.append( Magnitude(mag=0.5, magnitude_type='Mc', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) test_event.magnitudes.append( Magnitude(mag=1.3, magnitude_type='Ms', creation_info=CreationInfo('TES'), origin_id=test_event.origins[0].resource_id)) # Define the test pick _waveform_id_1 = WaveformStreamID(station_code='FOZ', channel_code='SHZ', network_code='NZ') _waveform_id_2 = WaveformStreamID(station_code='WTSZ', channel_code='BH1', network_code=' ') # Pick to associate with amplitude - 0 test_event.picks = [ Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, onset='impulsive', phase_hint='PN', polarity='positive', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_1, phase_hint='IAML', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.68, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='SG', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.72, evaluation_mode="manual"), Pick(waveform_id=_waveform_id_2, onset='impulsive', phase_hint='PN', polarity='undecidable', time=UTCDateTime("2012-03-26") + 1.62, evaluation_mode="automatic") ] # Test a generic local magnitude amplitude pick test_event.amplitudes = [ Amplitude(generic_amplitude=2.0, period=0.4, pick_id=test_event.picks[0].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', magnitude_hint='ML', category='point', type='AML'), Amplitude(generic_amplitude=10, pick_id=test_event.picks[1].resource_id, waveform_id=test_event.picks[1].waveform_id, type='END', category='duration', unit='s', magnitude_hint='Mc', snr=2.3), Amplitude(generic_amplitude=5.0, period=0.6, pick_id=test_event.picks[2].resource_id, waveform_id=test_event.picks[0].waveform_id, unit='m', category='point', type='AML') ] test_event.origins[0].arrivals = [ Arrival(time_weight=0, phase=test_event.picks[1].phase_hint, pick_id=test_event.picks[1].resource_id), Arrival(time_weight=2, phase=test_event.picks[3].phase_hint, pick_id=test_event.picks[3].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25), Arrival(time_weight=2, phase=test_event.picks[4].phase_hint, pick_id=test_event.picks[4].resource_id, backazimuth_residual=5, time_residual=0.2, distance=15, azimuth=25) ] # Add in error info (line E) test_event.origins[0].quality = OriginQuality(standard_error=0.01, azimuthal_gap=36) # Origin uncertainty in Seisan is output as long-lat-depth, quakeML has # semi-major and semi-minor test_event.origins[0].origin_uncertainty = OriginUncertainty( confidence_ellipsoid=ConfidenceEllipsoid( semi_major_axis_length=3000, semi_minor_axis_length=1000, semi_intermediate_axis_length=2000, major_axis_plunge=20, major_axis_azimuth=100, major_axis_rotation=4)) test_event.origins[0].time_errors = QuantityError(uncertainty=0.5) # Add in fault-plane solution info (line F) - Note have to check program # used to determine which fields are filled.... test_event.focal_mechanisms.append( FocalMechanism(nodal_planes=NodalPlanes( nodal_plane_1=NodalPlane(strike=180, dip=20, rake=30, strike_errors=QuantityError(10), dip_errors=QuantityError(10), rake_errors=QuantityError(20))), method_id=ResourceIdentifier( "smi:nc.anss.org/focalMechanism/FPFIT"), creation_info=CreationInfo(agency_id="NC"), misfit=0.5, station_distribution_ratio=0.8)) # Need to test high-precision origin and that it is preferred origin. # Moment tensor includes another origin test_event.origins.append( Origin(time=UTCDateTime("2012-03-26") + 1.2, latitude=45.1, longitude=25.2, depth=14500)) test_event.magnitudes.append( Magnitude(mag=0.1, magnitude_type='MW', creation_info=CreationInfo('TES'), origin_id=test_event.origins[-1].resource_id)) # Moment tensors go with focal-mechanisms test_event.focal_mechanisms.append( FocalMechanism(moment_tensor=MomentTensor( derived_origin_id=test_event.origins[-1].resource_id, moment_magnitude_id=test_event.magnitudes[-1].resource_id, scalar_moment=100, tensor=Tensor( m_rr=100, m_tt=100, m_pp=10, m_rt=1, m_rp=20, m_tp=15), method_id=ResourceIdentifier( 'smi:nc.anss.org/momentTensor/BLAH')))) return test_event
def setEventData(eventParser, arrivals, count): global originCount global eventCount global pickCount creation_info = CreationInfo( author='niket_engdahl_parser', creation_time=UTCDateTime(), agency_uri=ResourceIdentifier(id='smi:engdahl.ga.gov.au/ga-engdahl'), agency_id='ga-engdahl') # magnitudeSurface = Magnitude(resource_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/origin/'+str(originCount)+'#netMag.Ms'), # mag=eventParser.ms, # magnitude_type='Ms', # origin_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/origin/'+str(originCount)), # azimuthal_gap=eventParser.openaz2, # creation_info=creation_info) origin = Origin( resource_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/origin/' + str(originCount)), time=UTCDateTime(int(str(2000 + int(eventParser.iyr))), int(eventParser.mon), int(eventParser.iday), int(eventParser.ihr), int(eventParser.min), int(eventParser.sec.split('.')[0]), int(eventParser.sec.split('.')[1] + '0')), longitude=eventParser.glon, latitude=eventParser.glat, depth=float(eventParser.depth) * 1000, # engdahl files report kms, obspy expects m depth_errors=eventParser.sedep, method_id=ResourceIdentifier(id='EHB'), earth_model_id=ResourceIdentifier(id='ak135'), quality=OriginQuality(associated_phase_count=len(arrivals), used_phase_count=len(arrivals), standard_error=eventParser.se, azimuthal_gap=eventParser.openaz2), evaluation_mode='automatic', creation_info=creation_info) magnitude = Magnitude( resource_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/origin/' + str(originCount) + '#netMag.Mb'), mag=eventParser.mb, magnitude_type='Mb', origin_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/origin/' + str(originCount)), azimuthal_gap=eventParser.openaz1, creation_info=creation_info) originCount += 1 pickList = [] arrivalList = [] pPhaseArrival = None for arrParser in arrivals: pickOnset = None pol = None if arrParser.year and arrParser.month and arrParser.day and arrParser.station: pPhaseArrival = arrParser else: arrParser.year = pPhaseArrival.year arrParser.day = pPhaseArrival.day arrParser.month = pPhaseArrival.month arrParser.station = pPhaseArrival.station arrParser.delta = pPhaseArrival.delta arrParser.dtdd = pPhaseArrival.dtdd arrParser.backaz = pPhaseArrival.backaz arrParser.focalDip = pPhaseArrival.focalDip arrParser.angleAzimuth = pPhaseArrival.angleAzimuth if arrParser.phase1 == 'LR' or arrParser.phase2 == 'LR' or arrParser.hour == '24': continue if arrParser.phase1.startswith('i'): pickOnset = PickOnset.impulsive if arrParser.fm == '+': pol = PickPolarity.positive elif arrParser.fm == '-': pol = PickPolarity.negative elif arrParser.phase1.startswith('e'): pickOnset = PickOnset.emergent pick = Pick( resource_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/pick/' + str(pickCount)), time=UTCDateTime(int(str(2000 + int(arrParser.year))), int(arrParser.month), int(arrParser.day), int(arrParser.hour), int(arrParser.minute), int(arrParser.second.split('.')[0]), int(arrParser.second.split('.')[1] + '0')), waveform_id=WaveformStreamID(network_code='', station_code=arrParser.station, channel_code='BHZ'), methodID=ResourceIdentifier('STA/LTA'), backazimuth=arrParser.backaz if arrParser.backaz else None, onset=pickOnset, phase_hint=arrParser.phase, polarity=pol, evaluation_mode='automatic', # TO-DO comment='populate all the remaining fields here as key value', creation_info=creation_info) if not arrParser.backaz: print "arrParser.backaz is empty. printing the arrParser for debugging" pickCount += 1 pickList.append(pick) arrival = Arrival( pick_id=ResourceIdentifier(id='smi:engdahl.ga.gov.au/pick/' + str(pickCount - 1)), phase=arrParser.phase if arrParser.phase else None, azimuth=arrParser.backaz if arrParser.backaz else None, distance=arrParser.delta if arrParser.delta else None, # if the * has some significance, it should be accounted for. ignoring for now. time_residual=arrParser.residual.rstrip('*'), time_weight=arrParser.wgt if arrParser.wgt else None, backazimuth_weight=arrParser.wgt if arrParser.wgt else None) arrivalList.append(arrival) if not arrParser.wgt: print "arrParser.wgt is empty. printing the arrParser for debugging" # pprint.pprint(arrParser) origin.arrivals = arrivalList event = Event(resource_id=ResourceIdentifier( id='smi:engdahl.ga.gov.au/event/' + str(eventCount)), creation_info=creation_info, event_type='earthquake') eventCount += 1 event.picks = pickList event.origins = [ origin, ] event.magnitudes = [ magnitude, ] event.preferred_origin_id = origin.resource_id event.preferred_magnitude_id = magnitude.resource_id return event