def build(self): """ Build an obspy moment tensor focal mech event This makes the tensor output into an Event containing: 1) a FocalMechanism with a MomentTensor, NodalPlanes, and PrincipalAxes 2) a Magnitude of the Mw from the Tensor Which is what we want for outputting QuakeML using the (slightly modified) obspy code. Input ----- filehandle => open file OR str from filehandle.read() Output ------ event => instance of Event() class as described above """ p = self.parser event = Event(event_type='earthquake') origin = Origin() focal_mech = FocalMechanism() nodal_planes = NodalPlanes() moment_tensor = MomentTensor() principal_ax = PrincipalAxes() magnitude = Magnitude() data_used = DataUsed() creation_info = CreationInfo(agency_id='NN') ev_mode = 'automatic' ev_stat = 'preliminary' evid = None orid = None # Parse the entire file line by line. for n,l in enumerate(p.line): if 'REVIEWED BY NSL STAFF' in l: ev_mode = 'manual' ev_stat = 'reviewed' if 'Event ID' in l: evid = p._id(n) if 'Origin ID' in l: orid = p._id(n) if 'Ichinose' in l: moment_tensor.category = 'regional' if re.match(r'^\d{4}\/\d{2}\/\d{2}', l): ev = p._event_info(n) if 'Depth' in l: derived_depth = p._depth(n) if 'Mw' in l: magnitude.mag = p._mw(n) magnitude.magnitude_type = 'Mw' if 'Mo' in l and 'dyne' in l: moment_tensor.scalar_moment = p._mo(n) if 'Percent Double Couple' in l: moment_tensor.double_couple = p._percent(n) if 'Percent CLVD' in l: moment_tensor.clvd = p._percent(n) if 'Epsilon' in l: moment_tensor.variance = p._epsilon(n) if 'Percent Variance Reduction' in l: moment_tensor.variance_reduction = p._percent(n) if 'Major Double Couple' in l and 'strike' in p.line[n+1]: np = p._double_couple(n) nodal_planes.nodal_plane_1 = NodalPlane(*np[0]) nodal_planes.nodal_plane_2 = NodalPlane(*np[1]) nodal_planes.preferred_plane = 1 if 'Spherical Coordinates' in l: mt = p._mt_sphere(n) moment_tensor.tensor = Tensor( m_rr = mt['Mrr'], m_tt = mt['Mtt'], m_pp = mt['Mff'], m_rt = mt['Mrt'], m_rp = mt['Mrf'], m_tp = mt['Mtf'], ) if 'Eigenvalues and eigenvectors of the Major Double Couple' in l: ax = p._vectors(n) principal_ax.t_axis = Axis(ax['T']['trend'], ax['T']['plunge'], ax['T']['ev']) principal_ax.p_axis = Axis(ax['P']['trend'], ax['P']['plunge'], ax['P']['ev']) principal_ax.n_axis = Axis(ax['N']['trend'], ax['N']['plunge'], ax['N']['ev']) if 'Number of Stations' in l: data_used.station_count = p._number_of_stations(n) if 'Maximum' in l and 'Gap' in l: focal_mech.azimuthal_gap = p._gap(n) if re.match(r'^Date', l): creation_info.creation_time = p._creation_time(n) # Creation Time creation_info.version = orid # Fill in magnitude values magnitude.evaluation_mode = ev_mode magnitude.evaluation_status = ev_stat magnitude.creation_info = creation_info.copy() magnitude.resource_id = self._rid(magnitude) # Stub origin origin.time = ev.get('time') origin.latitude = ev.get('lat') origin.longitude = ev.get('lon') origin.depth = derived_depth * 1000. origin.depth_type = "from moment tensor inversion" origin.creation_info = creation_info.copy() # Unique from true origin ID _oid = self._rid(origin) origin.resource_id = ResourceIdentifier(str(_oid) + '/mt') del _oid # Make an id for the MT that references this origin ogid = str(origin.resource_id) doid = ResourceIdentifier(ogid, referred_object=origin) # Make an id for the moment tensor mag which references this mag mrid = str(magnitude.resource_id) mmid = ResourceIdentifier(mrid, referred_object=magnitude) # MT todo: could check/use URL for RID if parsing the php file moment_tensor.evaluation_mode = ev_mode moment_tensor.evaluation_status = ev_stat moment_tensor.data_used = data_used moment_tensor.moment_magnitude_id = mmid moment_tensor.derived_origin_id = doid moment_tensor.creation_info = creation_info.copy() moment_tensor.resource_id = self._rid(moment_tensor) # Fill in focal_mech values focal_mech.nodal_planes = nodal_planes focal_mech.moment_tensor = moment_tensor focal_mech.principal_axes = principal_ax focal_mech.creation_info = creation_info.copy() focal_mech.resource_id = self._rid(focal_mech) # add mech and new magnitude to event event.focal_mechanisms = [focal_mech] event.magnitudes = [magnitude] event.origins = [origin] event.creation_info = creation_info.copy() # If an MT was done, that's the preferred mag/mech event.preferred_magnitude_id = str(magnitude.resource_id) event.preferred_focal_mechanism_id = str(focal_mech.resource_id) if evid: event.creation_info.version = evid event.resource_id = self._rid(event) self.event = event
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)