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 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 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