def __toStationMagnitude(parser, stat_mag_el): """ Parses a given station magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type stat_mag_el: etree.element :param stat_mag_el: station magnitude element to be parsed. :return: A ObsPy :class:`~obspy.core.event.StationMagnitude` object. """ mag = StationMagnitude() mag.mag, mag.mag_errors = __toFloatQuantity(parser, stat_mag_el, "mag") # Use the waveform id to store station and channel(s) in the form # station.[channel_1, channel_2] or station.channel in the case only one # channel has been used. # XXX: This might be a violation of how this field is used within QuakeML channels = parser.xpath2obj('channels', stat_mag_el).split(',') channels = ','.join([_i.strip() for _i in channels]) if len(channels) > 1: channels = '%s' % channels station = parser.xpath2obj('station', stat_mag_el) mag.waveform_id = WaveformStreamID() mag.waveform_id.station_code = station mag.waveform_id.channel_code = channels weight_comment = Comment( text="Weight from the SeisHub event file: %.3f" % \ parser.xpath2obj("weight", stat_mag_el, float)) mag.comments.append(weight_comment) return mag
def __toStationMagnitude(parser, stat_mag_el): """ Parses a given station magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type stat_mag_el: etree.element :param stat_mag_el: station magnitude element to be parsed. return: A ObsPy :class:`~obspy.core.event.StationMagnitude` object. """ global CURRENT_TYPE mag = StationMagnitude() mag.mag, mag.mag_errors = __toFloatQuantity(parser, stat_mag_el, "mag") mag.resource_id = ResourceIdentifier( prefix="/".join([RESOURCE_ROOT, "station_magnitude"])) # Use the waveform id to store station and channel(s) in the form # station.[channel_1, channel_2] or station.channel in the case only one # channel has been used. # XXX: This might be a violation of how this field is used within QuakeML channels = parser.xpath2obj('channels', stat_mag_el).split(',') channels = ','.join([_i.strip() for _i in channels]) if len(channels) > 1: channels = '%s' % channels station = fix_station_name(parser.xpath2obj('station', stat_mag_el)) location = parser.xpath2obj('location', stat_mag_el, str) or "" mag.waveform_id = WaveformStreamID() # Map some station names. if station in STATION_DICT: station = STATION_DICT[station] mag.waveform_id.station_code = station if CURRENT_TYPE == "obspyck": mag.method_id = "%s/station_magnitude_method/obspyck/1" % RESOURCE_ROOT network = parser.xpath2obj('network', stat_mag_el) if network is None: # network id is not stored in original stationMagnitude, try to find it # in a pick with same station name for waveform in parser.xpath("pick/waveform"): if waveform.attrib.get("stationCode") == station: network = waveform.attrib.get("networkCode") break if network is None: network = NETWORK_DICT[station] if network is None: print "AAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHH" raise Exception if "," not in channels: mag.waveform_id.channel_code = channels mag.waveform_id.network_code = network mag.waveform_id.location_code = location return mag
def __toStationMagnitude(parser, stat_mag_el): """ Parses a given station magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type stat_mag_el: etree.element :param stat_mag_el: station magnitude element to be parsed. return: A ObsPy :class:`~obspy.core.event.StationMagnitude` object. """ global CURRENT_TYPE mag = StationMagnitude() mag.mag, mag.mag_errors = __toFloatQuantity(parser, stat_mag_el, "mag") mag.resource_id = ResourceIdentifier(prefix="/".join([RESOURCE_ROOT, "station_magnitude"])) # Use the waveform id to store station and channel(s) in the form # station.[channel_1, channel_2] or station.channel in the case only one # channel has been used. # XXX: This might be a violation of how this field is used within QuakeML channels = parser.xpath2obj('channels', stat_mag_el).split(',') channels = ','.join([_i.strip() for _i in channels]) if len(channels) > 1: channels = '%s' % channels station = fix_station_name(parser.xpath2obj('station', stat_mag_el)) location = parser.xpath2obj('location', stat_mag_el, str) or "" mag.waveform_id = WaveformStreamID() # Map some station names. if station in STATION_DICT: station = STATION_DICT[station] mag.waveform_id.station_code = station if CURRENT_TYPE == "obspyck": mag.method_id = "%s/station_magnitude_method/obspyck/1" % RESOURCE_ROOT network = parser.xpath2obj('network', stat_mag_el) if network is None: # network id is not stored in original stationMagnitude, try to find it # in a pick with same station name for waveform in parser.xpath("pick/waveform"): if waveform.attrib.get("stationCode") == station: network = waveform.attrib.get("networkCode") break if network is None: network = NETWORK_DICT[station] if network is None: print "AAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHH" raise Exception if "," not in channels: mag.waveform_id.channel_code = channels mag.waveform_id.network_code = network mag.waveform_id.location_code = location return mag
def _parseRecordP(self, line, event): """ Parses the 'primary phase record' P The primary phase is the first phase of the reading, regardless its type. """ station = line[2:7].strip() phase = line[7:15] arrival_time = line[15:24] residual = self._float(line[25:30]) #unused: residual_flag = line[30] distance = self._float(line[32:38]) # degrees azimuth = self._float(line[39:44]) backazimuth = round(azimuth % -360 + 180, 1) mb_period = self._float(line[44:48]) mb_amplitude = self._float(line[48:55]) # nanometers mb_magnitude = self._float(line[56:59]) #unused: mb_usage_flag = line[59] origin = event.origins[0] evid = event.resource_id.id.split('/')[-1] waveform_id = WaveformStreamID() waveform_id.station_code = station #network_code is required for QuakeML validation waveform_id.network_code = ' ' station_string =\ waveform_id.getSEEDString()\ .replace(' ', '-').replace('.', '_').lower() prefix = '/'.join( (res_id_prefix, 'waveformstream', evid, station_string)) waveform_id.resource_uri = ResourceIdentifier(prefix=prefix) pick = Pick() prefix = '/'.join((res_id_prefix, 'pick', evid, station_string)) pick.resource_id = ResourceIdentifier(prefix=prefix) date = origin.time.strftime('%Y%m%d') pick.time = UTCDateTime(date + arrival_time) #Check if pick is on the next day: if pick.time < origin.time: pick.time += timedelta(days=1) pick.waveform_id = waveform_id pick.backazimuth = backazimuth onset = phase[0] if onset == 'e': pick.onset = 'emergent' phase = phase[1:] elif onset == 'i': pick.onset = 'impulsive' phase = phase[1:] elif onset == 'q': pick.onset = 'questionable' phase = phase[1:] pick.phase_hint = phase.strip() event.picks.append(pick) if mb_amplitude is not None: amplitude = Amplitude() prefix = '/'.join((res_id_prefix, 'amp', evid, station_string)) amplitude.resource_id = ResourceIdentifier(prefix=prefix) amplitude.generic_amplitude = mb_amplitude * 1E-9 amplitude.unit = 'm' amplitude.period = mb_period amplitude.type = 'AB' amplitude.magnitude_hint = 'Mb' amplitude.pick_id = pick.resource_id amplitude.waveform_id = pick.waveform_id event.amplitudes.append(amplitude) station_magnitude = StationMagnitude() prefix = '/'.join( (res_id_prefix, 'stationmagntiude', evid, station_string)) station_magnitude.resource_id = ResourceIdentifier(prefix=prefix) station_magnitude.origin_id = origin.resource_id station_magnitude.mag = mb_magnitude #station_magnitude.mag_errors['uncertainty'] = 0.0 station_magnitude.station_magnitude_type = 'Mb' station_magnitude.amplitude_id = amplitude.resource_id station_magnitude.waveform_id = pick.waveform_id res_id = '/'.join( (res_id_prefix, 'magnitude/generic/body_wave_magnitude')) station_magnitude.method_id =\ ResourceIdentifier(id=res_id) event.station_magnitudes.append(station_magnitude) arrival = Arrival() prefix = '/'.join((res_id_prefix, 'arrival', evid, station_string)) arrival.resource_id = ResourceIdentifier(prefix=prefix) arrival.pick_id = pick.resource_id arrival.phase = pick.phase_hint arrival.azimuth = azimuth arrival.distance = distance arrival.time_residual = residual res_id = '/'.join((res_id_prefix, 'earthmodel/ak135')) arrival.earth_model_id = ResourceIdentifier(id=res_id) origin.arrivals.append(arrival) origin.quality.minimum_distance = min( d for d in (arrival.distance, origin.quality.minimum_distance) if d is not None) origin.quality.maximum_distance =\ max(arrival.distance, origin.quality.minimum_distance) origin.quality.associated_phase_count += 1 return pick, arrival
def _parse_arrivals(self, event, origin, origin_res_id): # Skip header of arrivals next(self.lines) # Stop the loop after 2 empty lines (according to the standard). previous_line_empty = False for line in self.lines: line_empty = not line or line.isspace() if not self.event_point_separator: # Event are separated by two empty lines if line_empty and previous_line_empty: break else: # Event are separated by '.' if line.startswith('.'): break previous_line_empty = line_empty if line_empty: # Skip empty lines when the loop should be stopped by # point continue magnitude_types = [] magnitude_values = [] fields = self.fields['arrival'] station = line[fields['sta']].strip() distance = line[fields['dist']].strip() event_azimuth = line[fields['ev_az']].strip() evaluation_mode = line[fields['picktype']].strip() direction = line[fields['direction']].strip() onset = line[fields['detchar']].strip() phase = line[fields['phase']].strip() time = line[fields['time']].strip().replace('/', '-') time_residual = line[fields['t_res']].strip() arrival_azimuth = line[fields['azim']].strip() azimuth_residual = line[fields['az_res']].strip() slowness = line[fields['slow']].strip() slowness_residual = line[fields['s_res']].strip() time_defining_flag = line[fields['t_def']].strip() azimuth_defining_flag = line[fields['a_def']].strip() slowness_defining_flag = line[fields['s_def']].strip() snr = line[fields['snr']].strip() amplitude_value = line[fields['amp']].strip() period = line[fields['per']].strip() magnitude_types.append(line[fields['mag_type_1']].strip()) magnitude_values.append(line[fields['mag_1']].strip()) magnitude_types.append(line[fields['mag_type_2']].strip()) magnitude_values.append(line[fields['mag_2']].strip()) line_id = line[fields['id']].strip() # Don't take pick and arrival with wrong time residual if '*' in time_residual: continue try: pick = Pick() pick.creation_info = self._get_creation_info() pick.waveform_id = WaveformStreamID() pick.waveform_id.station_code = station pick.time = UTCDateTime(time) network_code = self.default_network_code location_code = self.default_location_code channel_code = self.default_channel_code try: network_code, channel = self._get_channel( station, pick.time) if channel: channel_code = channel.code location_code = channel.location_code except TypeError: pass pick.waveform_id.network_code = network_code pick.waveform_id.channel_code = channel_code if location_code: pick.waveform_id.location_code = location_code try: ev_mode = EVALUATION_MODES[evaluation_mode] pick.evaluation_mode = ev_mode except KeyError: pass try: pick.polarity = PICK_POLARITIES[direction] except KeyError: pass try: pick.onset = PICK_ONSETS[onset] except KeyError: pass pick.phase_hint = phase try: pick.backazimuth = float(arrival_azimuth) except ValueError: pass try: pick.horizontal_slowness = float(slowness) except ValueError: pass public_id = "pick/%s" % line_id pick.resource_id = self._get_res_id(public_id) event.picks.append(pick) except (TypeError, ValueError, AttributeError): # Can't parse pick, skip arrival and amplitude parsing continue arrival = Arrival() arrival.creation_info = self._get_creation_info() try: arrival.pick_id = pick.resource_id.id except AttributeError: pass arrival.phase = phase try: arrival.azimuth = float(event_azimuth) except ValueError: pass try: arrival.distance = float(distance) except ValueError: pass try: arrival.time_residual = float(time_residual) except ValueError: pass try: arrival.backazimuth_residual = float(azimuth_residual) except ValueError: pass try: arrival.horizontal_slowness_residual = float(slowness_residual) except ValueError: pass if time_defining_flag == 'T': arrival.time_weight = 1 if azimuth_defining_flag == 'A': arrival.backazimuth_weight = 1 if slowness_defining_flag == 'S': arrival.horizontal_slowness_weight = 1 public_id = "arrival/%s" % line_id arrival.resource_id = self._get_res_id(public_id, parent_res_id=origin_res_id) origin.arrivals.append(arrival) try: amplitude = Amplitude() amplitude.creation_info = self._get_creation_info() amplitude.generic_amplitude = float(amplitude_value) try: amplitude.pick_id = pick.resource_id amplitude.waveform_id = pick.waveform_id except AttributeError: pass try: amplitude.period = float(period) except ValueError: pass try: amplitude.snr = float(snr) except ValueError: pass for i in [0, 1]: if magnitude_types[i] and not magnitude_types[i].isspace(): amplitude.magnitude_hint = magnitude_types[i] public_id = "amplitude/%s" % line_id amplitude.resource_id = self._get_res_id(public_id) event.amplitudes.append(amplitude) for i in [0, 1]: sta_mag = StationMagnitude() sta_mag.creation_info = self._get_creation_info() sta_mag.origin_id = origin_res_id sta_mag.amplitude_id = amplitude.resource_id sta_mag.station_magnitude_type = magnitude_types[i] sta_mag.mag = magnitude_values[i] sta_mag.waveform_id = pick.waveform_id public_id = "magnitude/station/%s/%s" % (line_id, i) sta_mag.resource_id = self._get_res_id(public_id) event.station_magnitudes.append(sta_mag) # Associate station mag with network mag of same type mag = self._find_magnitude_by_type(event, origin_res_id, magnitude_types[i]) if mag: contrib = StationMagnitudeContribution() contrib.station_magnitude_id = sta_mag.resource_id contrib.weight = 1.0 mag.station_magnitude_contributions.append(contrib) except ValueError: pass
def _parse_record_p(self, line, event): """ Parses the 'primary phase record' P The primary phase is the first phase of the reading, regardless its type. """ station = line[2:7].strip() phase = line[7:15] arrival_time = line[15:24] residual = self._float(line[25:30]) # unused: residual_flag = line[30] distance = self._float(line[32:38]) # degrees azimuth = self._float(line[39:44]) backazimuth = round(azimuth % -360 + 180, 1) mb_period = self._float(line[44:48]) mb_amplitude = self._float(line[48:55]) # nanometers mb_magnitude = self._float(line[56:59]) # unused: mb_usage_flag = line[59] origin = event.origins[0] evid = event.resource_id.id.split('/')[-1] waveform_id = WaveformStreamID() waveform_id.station_code = station # network_code is required for QuakeML validation waveform_id.network_code = ' ' station_string = \ waveform_id.get_seed_string()\ .replace(' ', '-').replace('.', '_').lower() prefix = '/'.join((res_id_prefix, 'waveformstream', evid, station_string)) waveform_id.resource_uri = ResourceIdentifier(prefix=prefix) pick = Pick() prefix = '/'.join((res_id_prefix, 'pick', evid, station_string)) pick.resource_id = ResourceIdentifier(prefix=prefix) date = origin.time.strftime('%Y%m%d') pick.time = UTCDateTime(date + arrival_time) # Check if pick is on the next day: if pick.time < origin.time: pick.time += timedelta(days=1) pick.waveform_id = waveform_id pick.backazimuth = backazimuth onset = phase[0] if onset == 'e': pick.onset = 'emergent' phase = phase[1:] elif onset == 'i': pick.onset = 'impulsive' phase = phase[1:] elif onset == 'q': pick.onset = 'questionable' phase = phase[1:] pick.phase_hint = phase.strip() event.picks.append(pick) if mb_amplitude is not None: amplitude = Amplitude() prefix = '/'.join((res_id_prefix, 'amp', evid, station_string)) amplitude.resource_id = ResourceIdentifier(prefix=prefix) amplitude.generic_amplitude = mb_amplitude * 1E-9 amplitude.unit = 'm' amplitude.period = mb_period amplitude.type = 'AB' amplitude.magnitude_hint = 'Mb' amplitude.pick_id = pick.resource_id amplitude.waveform_id = pick.waveform_id event.amplitudes.append(amplitude) station_magnitude = StationMagnitude() prefix = '/'.join((res_id_prefix, 'stationmagntiude', evid, station_string)) station_magnitude.resource_id = ResourceIdentifier(prefix=prefix) station_magnitude.origin_id = origin.resource_id station_magnitude.mag = mb_magnitude # station_magnitude.mag_errors['uncertainty'] = 0.0 station_magnitude.station_magnitude_type = 'Mb' station_magnitude.amplitude_id = amplitude.resource_id station_magnitude.waveform_id = pick.waveform_id res_id = '/'.join( (res_id_prefix, 'magnitude/generic/body_wave_magnitude')) station_magnitude.method_id = \ ResourceIdentifier(id=res_id) event.station_magnitudes.append(station_magnitude) arrival = Arrival() prefix = '/'.join((res_id_prefix, 'arrival', evid, station_string)) arrival.resource_id = ResourceIdentifier(prefix=prefix) arrival.pick_id = pick.resource_id arrival.phase = pick.phase_hint arrival.azimuth = azimuth arrival.distance = distance arrival.time_residual = residual res_id = '/'.join((res_id_prefix, 'earthmodel/ak135')) arrival.earth_model_id = ResourceIdentifier(id=res_id) origin.arrivals.append(arrival) origin.quality.minimum_distance = min( d for d in (arrival.distance, origin.quality.minimum_distance) if d is not None) origin.quality.maximum_distance = \ max(arrival.distance, origin.quality.minimum_distance) origin.quality.associated_phase_count += 1 return pick, arrival
def write_qml(config, sourcepar): if not config.options.qml_file: return qml_file = config.options.qml_file cat = read_events(qml_file) evid = config.hypo.evid try: ev = [e for e in cat if evid in str(e.resource_id)][0] except Exception: logging.warning('Unable to find evid "{}" in QuakeML file. ' 'QuakeML output will not be written.'.format(evid)) origin = ev.preferred_origin() if origin is None: origin = ev.origins[0] origin_id = origin.resource_id origin_id_strip = origin_id.id.split('/')[-1] origin_id_strip = origin_id_strip.replace(config.smi_strip_from_origin_id, '') # Common parameters ssp_version = get_versions()['version'] method_id = config.smi_base + '/sourcespec/' + ssp_version cr_info = CreationInfo() cr_info.agency_id = config.agency_id if config.author is None: author = '{}@{}'.format(getuser(), gethostname()) else: author = config.author cr_info.author = author cr_info.creation_time = UTCDateTime() means = sourcepar.means_weight errors = sourcepar.errors_weight stationpar = sourcepar.station_parameters # Magnitude mag = Magnitude() _id = config.smi_magnitude_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) mag.resource_id = ResourceIdentifier(id=_id) mag.method_id = ResourceIdentifier(id=method_id) mag.origin_id = origin_id mag.magnitude_type = 'Mw' mag.mag = means['Mw'] mag_err = QuantityError() mag_err.uncertainty = errors['Mw'] mag_err.confidence_level = 68.2 mag.mag_errors = mag_err mag.station_count = len([_s for _s in stationpar.keys()]) mag.evaluation_mode = 'automatic' mag.creation_info = cr_info # Seismic moment -- It has to be stored in a MomentTensor object # which, in turn, is part of a FocalMechanism object mt = MomentTensor() _id = config.smi_moment_tensor_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) mt.resource_id = ResourceIdentifier(id=_id) mt.derived_origin_id = origin_id mt.moment_magnitude_id = mag.resource_id mt.scalar_moment = means['Mo'] mt_err = QuantityError() mt_err.lower_uncertainty = errors['Mo'][0] mt_err.upper_uncertainty = errors['Mo'][1] mt_err.confidence_level = 68.2 mt.scalar_moment_errors = mt_err mt.method_id = method_id mt.creation_info = cr_info # And here is the FocalMechanism object fm = FocalMechanism() _id = config.smi_focal_mechanism_template.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$ORIGIN_ID', origin_id_strip) fm.resource_id = ResourceIdentifier(id=_id) fm.triggering_origin_id = origin_id fm.method_id = ResourceIdentifier(id=method_id) fm.moment_tensor = mt fm.creation_info = cr_info ev.focal_mechanisms.append(fm) # Station magnitudes for statId in sorted(stationpar.keys()): par = stationpar[statId] st_mag = StationMagnitude() seed_id = statId.split()[0] _id = config.smi_station_magnitude_template.replace( '$SMI_MAGNITUDE_TEMPLATE', config.smi_magnitude_template) _id = _id.replace('$ORIGIN_ID', origin_id_strip) _id = _id.replace('$SMI_BASE', config.smi_base) _id = _id.replace('$WAVEFORM_ID', seed_id) st_mag.resource_id = ResourceIdentifier(id=_id) st_mag.origin_id = origin_id st_mag.mag = par['Mw'] st_mag.station_magnitude_type = 'Mw' st_mag.method_id = mag.method_id st_mag.creation_info = cr_info st_mag.waveform_id = WaveformStreamID(seed_string=seed_id) st_mag.extra = SSPExtra() st_mag.extra.moment = SSPTag(par['Mo']) st_mag.extra.corner_frequency = SSPTag(par['fc']) st_mag.extra.t_star = SSPTag(par['t_star']) ev.station_magnitudes.append(st_mag) st_mag_contrib = StationMagnitudeContribution() st_mag_contrib.station_magnitude_id = st_mag.resource_id mag.station_magnitude_contributions.append(st_mag_contrib) ev.magnitudes.append(mag) # Write other average parameters as custom tags ev.extra = SSPExtra() ev.extra.corner_frequency = SSPContainerTag() ev.extra.corner_frequency.value.value = SSPTag(means['fc']) ev.extra.corner_frequency.value.lower_uncertainty =\ SSPTag(errors['fc'][0]) ev.extra.corner_frequency.value.upper_uncertainty =\ SSPTag(errors['fc'][1]) ev.extra.corner_frequency.value.confidence_level = SSPTag(68.2) ev.extra.t_star = SSPContainerTag() ev.extra.t_star.value.value = SSPTag(means['t_star']) ev.extra.t_star.value.uncertainty = SSPTag(errors['t_star']) ev.extra.t_star.value.confidence_level = SSPTag(68.2) ev.extra.source_radius = SSPContainerTag() ev.extra.source_radius.value.value = SSPTag(means['ra']) ev.extra.source_radius.value.lower_uncertainty =\ SSPTag(errors['ra'][0]) ev.extra.source_radius.value.upper_uncertainty =\ SSPTag(errors['ra'][1]) ev.extra.source_radius.value.confidence_level = SSPTag(68.2) ev.extra.stress_drop = SSPContainerTag() ev.extra.stress_drop.value.value = SSPTag(means['bsd']) ev.extra.stress_drop.value.lower_uncertainty =\ SSPTag(errors['bsd'][0]) ev.extra.stress_drop.value.upper_uncertainty =\ SSPTag(errors['bsd'][1]) ev.extra.stress_drop.value.confidence_level = SSPTag(68.2) if config.set_preferred_magnitude: ev.preferred_magnitude_id = mag.resource_id.id qml_file_out = os.path.join(config.options.outdir, evid + '.xml') ev.write(qml_file_out, format='QUAKEML') logging.info('QuakeML file written to: ' + qml_file_out)