def read_cat_ref(cat_file): """ Parses a given refrence catalogue (in ascii format,see the header for details) output is Obspy catalogue object """ cat_ref = np.loadtxt(cat_file,delimiter=',',skiprows=1) cat = Catalog() for i,e in enumerate(cat_ref): event = Event(resource_id='smi:local/='+str(i),creation_info='HG') origin = Origin() origin.time = UTCDateTime(int(e[2]),int(e[3]),int(e[4]), int(e[7]),int(e[8]),e[9]) origin.longitude = e[0] origin.latitude = e[1] origin.depth = e[6] * 1000. #in meters event.origins.append(origin) if ~(np.isnan(e[10])): mag = Magnitude(creation_info='HER') mag.mag = e[10] mag.magnitude_type = 'Mw' event.magnitudes.append(mag) if ~(np.isnan(e[11])): mag = Magnitude(creation_info='MAR') mag.mag = e[11] mag.magnitude_type = 'Mw' event.magnitudes.append(mag) if ~(np.isnan(e[12])): mag = Magnitude(creation_info='SIP') mag.mag = e[12] mag.magnitude_type = 'Mw' event.magnitudes.append(mag) cat.append(event) return cat
def _parseRecordAE(self, line, event): """ Parses the 'additional hypocenter error and magnitude record' AE """ orig_time_stderr = self._floatUnused(line[2:7]) latitude_stderr = self._floatUnused(line[8:14]) longitude_stderr = self._floatUnused(line[15:21]) depth_stderr = self._floatUnused(line[22:27]) gap = self._floatUnused(line[28:33]) mag1 = self._float(line[33:36]) mag1_type = line[36:38] mag2 = self._float(line[43:46]) mag2_type = line[46:48] evid = event.resource_id.id.split('/')[-1] #this record is to be associated to the latest origin origin = event.origins[-1] self._storeUncertainty(origin.time_errors, orig_time_stderr) self._storeUncertainty(origin.latitude_errors, self._latErrToDeg(latitude_stderr)) self._storeUncertainty( origin.longitude_errors, self._lonErrToDeg(longitude_stderr, origin.latitude)) self._storeUncertainty(origin.depth_errors, depth_stderr, scale=1000) origin.quality.azimuthal_gap = gap if mag1 > 0: mag = Magnitude() mag1_id = mag1_type.lower() res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag1_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo( agency_id=origin.creation_info.agency_id) mag.mag = mag1 mag.magnitude_type = mag1_type mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag2 > 0: mag = Magnitude() mag2_id = mag2_type.lower() if mag2_id == mag1_id: mag2_id += '2' res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag2_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo( agency_id=origin.creation_info.agency_id) mag.mag = mag2 mag.magnitude_type = mag2_type mag.origin_id = origin.resource_id event.magnitudes.append(mag)
def _parse_record_ae(self, line, event): """ Parses the 'additional hypocenter error and magnitude record' AE """ orig_time_stderr = self._float_unused(line[2:7]) latitude_stderr = self._float_unused(line[8:14]) longitude_stderr = self._float_unused(line[15:21]) depth_stderr = self._float_unused(line[22:27]) gap = self._float_unused(line[28:33]) mag1 = self._float(line[33:36]) mag1_type = line[36:38] mag2 = self._float(line[43:46]) mag2_type = line[46:48] evid = event.resource_id.id.split('/')[-1] # this record is to be associated to the latest origin origin = event.origins[-1] self._store_uncertainty(origin.time_errors, orig_time_stderr) self._store_uncertainty(origin.latitude_errors, self._lat_err_to_deg(latitude_stderr)) self._store_uncertainty(origin.longitude_errors, self._lon_err_to_deg(longitude_stderr, origin.latitude)) self._store_uncertainty(origin.depth_errors, depth_stderr, scale=1000) origin.quality.azimuthal_gap = gap if mag1 > 0: mag = Magnitude() mag1_id = mag1_type.lower() res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag1_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo( agency_id=origin.creation_info.agency_id) mag.mag = mag1 mag.magnitude_type = mag1_type mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag2 > 0: mag = Magnitude() mag2_id = mag2_type.lower() if mag2_id == mag1_id: mag2_id += '2' res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag2_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo( agency_id=origin.creation_info.agency_id) mag.mag = mag2 mag.magnitude_type = mag2_type mag.origin_id = origin.resource_id event.magnitudes.append(mag)
def _map_origin2magnitude(self, db, mtype='ml'): """ Return an obspy Magnitude from an dict of CSS key/values corresponding to one record. Inputs ====== db : dict of key/values of CSS fields from the 'origin' table Returns ======= obspy.core.event.Magnitude Notes ===== Any object that supports the dict 'get' method can be passed as input, e.g. OrderedDict, custom classes, etc. """ m = Magnitude() m.mag = db.get(mtype) m.magnitude_type = mtype m.creation_info = CreationInfo( creation_time = _utc(db.get('lddate')), agency_id = self.agency, version = db.get('orid'), author = db.get('auth'), ) if m.creation_info.author.startswith('orb'): m.evaluation_status = "preliminary" else: m.evaluation_status = "reviewed" m.resource_id = self._rid(m) return m
def get_event_object(self): ''' update events otime,lat,lon and mag with IRIS (or any other clients) catalog ''' # get parameters from the cataog if self.use_catalog == 1: print("WARNING using event data from the IRIS catalog") cat = self.client.get_events( starttime=self.otime - self.sec_before_after_event, endtime=self.otime + self.sec_before_after_event) self.ev = cat[0] # use catalog parameters self.otime = self.ev.origins[0].time self.elat = self.ev.origins[0].latitude self.elon = self.ev.origins[0].longitude self.edep = self.ev.origins[0].depth self.emag = self.ev.magnitudes[0].mag # use parameters from the input file else: print("WARNING using event data from user-defined catalog") #self.ev = Event() org = Origin() org.latitude = self.elat org.longitude = self.elon org.depth = self.edep org.time = self.otime mag = Magnitude() mag.mag = self.emag mag.magnitude_type = "Mw" self.ev.origins.append(org) self.ev.magnitudes.append(mag)
def __toMagnitude(parser, magnitude_el, origin): """ Parses a given magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type magnitude_el: etree.element :param magnitude_el: magnitude element to be parsed. :return: A ObsPy :class:`~obspy.core.event.Magnitude` object. """ global CURRENT_TYPE mag = Magnitude() mag.resource_id = ResourceIdentifier(prefix="/".join([RESOURCE_ROOT, "magnitude"])) mag.origin_id = origin.resource_id mag.mag, mag.mag_errors = __toFloatQuantity(parser, magnitude_el, "mag") # obspyck used to write variance (instead of std) in magnitude error fields if CURRENT_TYPE == "obspyck": if mag.mag_errors.uncertainty is not None: mag.mag_errors.uncertainty = math.sqrt(mag.mag_errors.uncertainty) mag.magnitude_type = parser.xpath2obj("type", magnitude_el) mag.station_count = parser.xpath2obj("stationCount", magnitude_el, int) mag.method_id = "%s/magnitude_method/%s/1" % (RESOURCE_ROOT, parser.xpath2obj('program', magnitude_el)) if str(mag.method_id).lower().endswith("none"): mag.method_id = None return mag
def __toMagnitude(parser, magnitude_el, origin): """ Parses a given magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type magnitude_el: etree.element :param magnitude_el: magnitude element to be parsed. :return: A ObsPy :class:`~obspy.core.event.Magnitude` object. """ global CURRENT_TYPE mag = Magnitude() mag.resource_id = ResourceIdentifier( prefix="/".join([RESOURCE_ROOT, "magnitude"])) mag.origin_id = origin.resource_id mag.mag, mag.mag_errors = __toFloatQuantity(parser, magnitude_el, "mag") # obspyck used to write variance (instead of std) in magnitude error fields if CURRENT_TYPE == "obspyck": if mag.mag_errors.uncertainty is not None: mag.mag_errors.uncertainty = math.sqrt(mag.mag_errors.uncertainty) mag.mag_errors.confidence_level = 68.3 mag.magnitude_type = parser.xpath2obj("type", magnitude_el) mag.station_count = parser.xpath2obj("stationCount", magnitude_el, int) mag.method_id = "%s/magnitude_method/%s/1" % ( RESOURCE_ROOT, parser.xpath2obj('program', magnitude_el)) if str(mag.method_id).lower().endswith("none"): mag.method_id = None return mag
def __toMagnitude(parser, magnitude_el): """ Parses a given magnitude etree element. :type parser: :class:`~obspy.core.util.xmlwrapper.XMLParser` :param parser: Open XMLParser object. :type magnitude_el: etree.element :param magnitude_el: magnitude element to be parsed. :return: A ObsPy :class:`~obspy.core.event.Magnitude` object. """ mag = Magnitude() mag.mag, mag.mag_errors = __toFloatQuantity(parser, magnitude_el, "mag") mag.magnitude_type = parser.xpath2obj("type", magnitude_el) mag.station_count = parser.xpath2obj("stationCount", magnitude_el, int) mag.method_id = parser.xpath2obj("program", magnitude_el) return mag
def event_to_quakeml(event, filename): """ Write one of those events to QuakeML. """ # Create all objects. cat = Catalog() ev = Event() org = Origin() mag = Magnitude() fm = FocalMechanism() mt = MomentTensor() t = Tensor() # Link them together. cat.append(ev) ev.origins.append(org) ev.magnitudes.append(mag) ev.focal_mechanisms.append(fm) fm.moment_tensor = mt mt.tensor = t # Fill values ev.resource_id = "smi:inversion/%s" % str(event["identifier"]) org.time = event["time"] org.longitude = event["longitude"] org.latitude = event["latitude"] org.depth = event["depth_in_km"] * 1000 mag.mag = event["Mw"] mag.magnitude_type = "Mw" t.m_rr = event["Mrr"] t.m_tt = event["Mpp"] t.m_pp = event["Mtt"] t.m_rt = event["Mrt"] t.m_rp = event["Mrp"] t.m_tp = event["Mtp"] cat.write(filename, format="quakeml")
def _map_netmag2magnitude(self, db): """ Return an obspy Magnitude from an dict of CSS key/values corresponding to one record. Inputs ====== db : dict of key/values of CSS fields from the 'netmag' table Returns ======= obspy.core.event.Magnitude Notes ===== Any object that supports the dict 'get' method can be passed as input, e.g. OrderedDict, custom classes, etc. """ m = Magnitude() m.mag = db.get('magnitude') m.magnitude_type = db.get('magtype') m.mag_errors.uncertainty = db.get('uncertainty') m.station_count = db.get('nsta') posted_author = _str(db.get('auth')) mode, status = self.get_event_status(posted_author) m.evaluation_mode = mode m.evaluation_status = status m.creation_info = CreationInfo( creation_time = _utc(db.get('lddate')), agency_id = self.agency, version = db.get('magid'), author = posted_author, ) m.resource_id = self._rid(m) return m
def _on_file_save(self): """ Creates a new obspy.core.event.Magnitude object and writes the moment magnitude to it. """ # Get the save filename. filename = QtGui.QFileDialog.getSaveFileName(caption="Save as...") filename = os.path.abspath(str(filename)) mag = Magnitude() mag.mag = self.final_result["moment_magnitude"] mag.magnitude_type = "Mw" mag.station_count = self.final_result["station_count"] mag.evaluation_mode = "manual" # Link to the used origin. mag.origin_id = self.current_state["event"].origins[0].resource_id mag.method_id = "Magnitude picker Krischer" # XXX: Potentially change once this program gets more stable. mag.evaluation_status = "preliminary" # Write the other results as Comments. mag.comments.append( \ Comment("Seismic moment in Nm: %g" % \ self.final_result["seismic_moment"])) mag.comments.append( \ Comment("Circular source radius in m: %.2f" % \ self.final_result["source_radius"])) mag.comments.append( \ Comment("Stress drop in Pa: %.2f" % \ self.final_result["stress_drop"])) mag.comments.append( \ Comment("Very rough Q estimation: %.1f" % \ self.final_result["quality_factor"])) event = copy.deepcopy(self.current_state["event"]) event.magnitudes.append(mag) cat = Catalog() cat.events.append(event) cat.write(filename, format="quakeml")
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
# if code=="WITA" or code=="AWST": # start_time-=28800 # Build event object event = Event(resource_id='GG_cat_' + str(event_num), creation_info='JG') event_num += 1 origin = Origin() origin.time = start_time origin.longitude = lon origin.latitude = lat origin.depth = dep event.origins.append(origin) mag = Magnitude(creation_info='GG_cat') mag.mag = mag_pref mag.magnitude_type = mag_type event.magnitudes.append(mag) ''' the time window to request the data will be 20 minutes, check maximum travel time and increase this value accordingly ''' end_time = start_time + 1200 # 20 minutes - to catch ~Rayleigh waves at 20 degrees distance (assume v>=3km/s) ''' get all waveform data available, use wildcards to reduce the data volume and speedup the process, unfortunately we need to request few times for every number of characters that forms the station name ''' st_3 = client.get_waveforms("AU", "???", "", "[BS]?[ENZ]", start_time, end_time) st_4 = client.get_waveforms("AU", "????", "", "[BS]?[ENZ]", start_time, end_time) if len(st_4) > 0: st = st_3 + st_4 else: st = st_3 print st # Cleanup duplicate traces returned by server
def _parse_first_line_origin(self, line, event, magnitudes): """ Parse the first line of origin data. :type line: str :param line: Line to parse. :type event: :class:`~obspy.core.event.event.Event` :param event: Event of the origin. :type magnitudes: list of :class:`~obspy.core.event.magnitude.Magnitude` :param magnitudes: Store magnitudes in a list to keep their positions. :rtype: :class:`~obspy.core.event.origin.Origin`, :class:`~obspy.core.event.resourceid.ResourceIdentifier` :returns: Parsed origin or None, resource identifier of the origin. """ magnitude_types = [] magnitude_values = [] magnitude_station_counts = [] fields = self.fields['line_1'] time_origin = line[fields['time']].strip() time_fixed_flag = line[fields['time_fixf']].strip() latitude = line[fields['lat']].strip() longitude = line[fields['lon']].strip() epicenter_fixed_flag = line[fields['epicenter_fixf']].strip() depth = line[fields['depth']].strip() depth_fixed_flag = line[fields['depth_fixf']].strip() phase_count = line[fields['n_def']].strip() station_count = line[fields['n_sta']].strip() azimuthal_gap = line[fields['gap']].strip() magnitude_types.append(line[fields['mag_type_1']].strip()) magnitude_values.append(line[fields['mag_1']].strip()) magnitude_station_counts.append(line[fields['mag_n_sta_1']].strip()) magnitude_types.append(line[fields['mag_type_2']].strip()) magnitude_values.append(line[fields['mag_2']].strip()) magnitude_station_counts.append(line[fields['mag_n_sta_2']].strip()) magnitude_types.append(line[fields['mag_type_3']].strip()) magnitude_values.append(line[fields['mag_3']].strip()) magnitude_station_counts.append(line[fields['mag_n_sta_3']].strip()) author = line[fields['author']].strip() origin_id = line[fields['id']].strip() origin = Origin() origin.quality = OriginQuality() try: origin.time = UTCDateTime(time_origin.replace('/', '-')) origin.latitude = float(latitude) origin.longitude = float(longitude) except (TypeError, ValueError): self._warn('Missing origin data, skipping event') return None, None origin.time_fixed = time_fixed_flag.lower() == 'f' origin.epicenter_fixed = epicenter_fixed_flag.lower() == 'f' try: # Convert value from km to m origin.depth = float(depth) * 1000 except ValueError: pass try: origin.depth_type = DEPTH_TYPES[depth_fixed_flag] except KeyError: origin.depth_type = OriginDepthType('from location') try: origin.quality.used_phase_count = int(phase_count) origin.quality.associated_phase_count = int(phase_count) except ValueError: pass try: origin.quality.used_station_count = int(station_count) origin.quality.associated_station_count = int(station_count) except ValueError: pass try: origin.quality.azimuthal_gap = float(azimuthal_gap) except ValueError: pass self.author = author origin.creation_info = self._get_creation_info() public_id = "origin/%s" % origin_id origin_res_id = self._get_res_id(public_id) for i in range(3): try: magnitude = Magnitude() magnitude.creation_info = self._get_creation_info() magnitude.magnitude_type = magnitude_types[i] magnitude.mag = float(magnitude_values[i]) magnitude.station_count = int(magnitude_station_counts[i]) magnitude.origin_id = origin_res_id magnitudes.append(magnitude) event.magnitudes.append(magnitude) except ValueError: # Magnitude can be empty but we need to keep the # position between mag1, mag2 or mag3. magnitudes.append(None) return origin, origin_res_id
def iris2quakeml(url, output_folder=None): if not "/spudservice/" in url: url = url.replace("/spud/", "/spudservice/") if url.endswith("/"): url += "quakeml" else: url += "/quakeml" print "Downloading %s..." % url r = requests.get(url) if r.status_code != 200: msg = "Error Downloading file!" raise Exception(msg) # For some reason the quakeml file is escaped HTML. h = HTMLParser.HTMLParser() data = h.unescape(r.content) # Replace some XML tags. data = data.replace("long-period body waves", "body waves") data = data.replace("intermediate-period surface waves", "surface waves") data = data.replace("long-period mantle waves", "mantle waves") data = data.replace("<html><body><pre>", "") data = data.replace("</pre></body></html>", "") # Change the resource identifiers. Colons are not allowed in QuakeML. pattern = r"(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{6})" data = re.sub(pattern, r"\1-\2-\3T\4-\5-\6.\7", data) data = StringIO(data) try: cat = readEvents(data) except: msg = "Could not read downloaded event data" raise ValueError(msg) # Parse the event, and use only one origin, magnitude and focal mechanism. # Only the first event is used. Should not be a problem for the chosen # global cmt application. ev = cat[0] if ev.preferred_origin(): ev.origins = [ev.preferred_origin()] else: ev.origins = [ev.origins[0]] if ev.preferred_focal_mechanism(): ev.focal_mechanisms = [ev.preferred_focal_mechanism()] else: ev.focal_mechanisms = [ev.focal_mechanisms[0]] try: mt = ev.focal_mechanisms[0].moment_tensor except: msg = "No moment tensor found in file." raise ValueError seismic_moment_in_dyn_cm = mt.scalar_moment if not seismic_moment_in_dyn_cm: msg = "No scalar moment found in file." raise ValueError(msg) # Create a new magnitude object with the moment magnitude calculated from # the given seismic moment. mag = Magnitude() mag.magnitude_type = "Mw" mag.origin_id = ev.origins[0].resource_id # This is the formula given on the GCMT homepage. mag.mag = (2.0 / 3.0) * (math.log10(seismic_moment_in_dyn_cm) - 16.1) mag.resource_id = ev.origins[0].resource_id.resource_id.replace("Origin", "Magnitude") ev.magnitudes = [mag] ev.preferred_magnitude_id = mag.resource_id # Convert the depth to meters. org = ev.origins[0] org.depth *= 1000.0 if org.depth_errors.uncertainty: org.depth_errors.uncertainty *= 1000.0 # Ugly asserts -- this is just a simple script. assert(len(ev.magnitudes) == 1) assert(len(ev.origins) == 1) assert(len(ev.focal_mechanisms) == 1) # All values given in the QuakeML file are given in dyne * cm. Convert them # to N * m. for key, value in mt.tensor.iteritems(): if key.startswith("m_") and len(key) == 4: mt.tensor[key] /= 1E7 if key.endswith("_errors") and hasattr(value, "uncertainty"): mt.tensor[key].uncertainty /= 1E7 mt.scalar_moment /= 1E7 if mt.scalar_moment_errors.uncertainty: mt.scalar_moment_errors.uncertainty /= 1E7 p_axes = ev.focal_mechanisms[0].principal_axes for ax in [p_axes.t_axis, p_axes.p_axis, p_axes.n_axis]: if ax is None or not ax.length: continue ax.length /= 1E7 # Check if it has a source time function stf = mt.source_time_function if stf: if stf.type != "triangle": msg = ("Source time function type '%s' not yet mapped. Please " "contact the developers.") % stf.type raise NotImplementedError(msg) if not stf.duration: if not stf.decay_time: msg = "Not known how to derive duration without decay time." raise NotImplementedError(msg) # Approximate the duraction for triangular STF. stf.duration = 2 * stf.decay_time # Get the flinn_engdahl region for a nice name. fe = FlinnEngdahl() region_name = fe.get_region(ev.origins[0].longitude, ev.origins[0].latitude) region_name = region_name.replace(" ", "_") event_name = "GCMT_event_%s_Mag_%.1f_%s-%s-%s-%s-%s.xml" % \ (region_name, ev.magnitudes[0].mag, ev.origins[0].time.year, ev.origins[0].time.month, ev.origins[0].time.day, ev.origins[0].time.hour, ev.origins[0].time.minute) # Check if the ids of the magnitude and origin contain the corresponding # tag. Otherwise replace tme. ev.origins[0].resource_id = ev.origins[0].resource_id.resource_id.replace( "quakeml/gcmtid", "quakeml/origin/gcmtid") ev.magnitudes[0].resource_id = \ ev.magnitudes[0].resource_id.resource_id.replace( "quakeml/gcmtid", "quakeml/magnitude/gcmtid") # Fix up the moment tensor resource_ids. mt.derived_origin_id = ev.origins[0].resource_id mt.resource_id = mt.resource_id.resource_id.replace("focalmechanism", "momenttensor") cat = Catalog() cat.resource_id = ev.origins[0].resource_id.resource_id.replace("origin", "event_parameters") cat.append(ev) if output_folder: event_name = os.path.join(output_folder, event_name) cat.write(event_name, format="quakeml", validate=True) print "Written file", event_name
def par2quakeml(Par_filename, QuakeML_filename, rotation_axis=[0.0, 1.0, 0.0], rotation_angle=-57.5, origin_time="2000-01-01 00:00:00.0", event_type="other event"): # initialise event ev = Event() # open and read Par file fid = open(Par_filename, 'r') fid.readline() fid.readline() fid.readline() fid.readline() lat_old = 90.0 - float(fid.readline().strip().split()[0]) lon_old = float(fid.readline().strip().split()[0]) depth = float(fid.readline().strip().split()[0]) fid.readline() Mtt_old = float(fid.readline().strip().split()[0]) Mpp_old = float(fid.readline().strip().split()[0]) Mrr_old = float(fid.readline().strip().split()[0]) Mtp_old = float(fid.readline().strip().split()[0]) Mtr_old = float(fid.readline().strip().split()[0]) Mpr_old = float(fid.readline().strip().split()[0]) # rotate event into physical domain lat, lon = rot.rotate_lat_lon(lat_old, lon_old, rotation_axis, rotation_angle) Mrr, Mtt, Mpp, Mtr, Mpr, Mtp = rot.rotate_moment_tensor( Mrr_old, Mtt_old, Mpp_old, Mtr_old, Mpr_old, Mtp_old, lat_old, lon_old, rotation_axis, rotation_angle) # populate event origin data ev.event_type = event_type ev_origin = Origin() ev_origin.time = UTCDateTime(origin_time) ev_origin.latitude = lat ev_origin.longitude = lon ev_origin.depth = depth ev.origins.append(ev_origin) # populte event moment tensor ev_tensor = Tensor() ev_tensor.m_rr = Mrr ev_tensor.m_tt = Mtt ev_tensor.m_pp = Mpp ev_tensor.m_rt = Mtr ev_tensor.m_rp = Mpr ev_tensor.m_tp = Mtp ev_momenttensor = MomentTensor() ev_momenttensor.tensor = ev_tensor ev_momenttensor.scalar_moment = np.sqrt(Mrr**2 + Mtt**2 + Mpp**2 + Mtr**2 + Mpr**2 + Mtp**2) ev_focalmechanism = FocalMechanism() ev_focalmechanism.moment_tensor = ev_momenttensor ev_focalmechanism.nodal_planes = NodalPlanes().setdefault(0, 0) ev.focal_mechanisms.append(ev_focalmechanism) # populate event magnitude ev_magnitude = Magnitude() ev_magnitude.mag = 0.667 * (np.log10(ev_momenttensor.scalar_moment) - 9.1) ev_magnitude.magnitude_type = 'Mw' ev.magnitudes.append(ev_magnitude) # write QuakeML file cat = Catalog() cat.append(ev) cat.write(QuakeML_filename, format="quakeml") # clean up fid.close()
def _read_single_event(event_file, locate_dir, units, local_mag_ph): """ Parse an event file from QuakeMigrate into an obspy Event object. Parameters ---------- event_file : `pathlib.Path` object Path to .event file to read. locate_dir : `pathlib.Path` object Path to locate directory (contains "events", "picks" etc. directories). units : {"km", "m"} Grid projection coordinates for QM LUT (determines units of depths and uncertainties in the .event files). local_mag_ph : {"S", "P"} Amplitude measurement used to calculate local magnitudes. Returns ------- event : `obspy.Event` object Event object populated with all available information output by :class:`~quakemigrate.signal.scan.locate()`, including event locations and uncertainties, picks, and amplitudes and magnitudes if available. """ # Parse information from event file event_info = pd.read_csv(event_file).iloc[0] event_uid = str(event_info["EventID"]) # Set distance conversion factor (from units of QM LUT projection units). if units == "km": factor = 1e3 elif units == "m": factor = 1 else: raise AttributeError(f"units must be 'km' or 'm'; not {units}") # Create event object to store origin and pick information event = Event() event.extra = AttribDict() event.resource_id = str(event_info["EventID"]) event.creation_info = CreationInfo(author="QuakeMigrate", version=quakemigrate.__version__) # Add COA info to extra event.extra.coa = {"value": event_info["COA"], "namespace": ns} event.extra.coa_norm = {"value": event_info["COA_NORM"], "namespace": ns} event.extra.trig_coa = {"value": event_info["TRIG_COA"], "namespace": ns} event.extra.dec_coa = {"value": event_info["DEC_COA"], "namespace": ns} event.extra.dec_coa_norm = { "value": event_info["DEC_COA_NORM"], "namespace": ns } # Determine location of cut waveform data - add to event object as a # custom extra attribute. mseed = locate_dir / "raw_cut_waveforms" / event_uid event.extra.cut_waveforms_file = { "value": str(mseed.with_suffix(".m").resolve()), "namespace": ns } if (locate_dir / "real_cut_waveforms").exists(): mseed = locate_dir / "real_cut_waveforms" / event_uid event.extra.real_cut_waveforms_file = { "value": str(mseed.with_suffix(".m").resolve()), "namespace": ns } if (locate_dir / "wa_cut_waveforms").exists(): mseed = locate_dir / "wa_cut_waveforms" / event_uid event.extra.wa_cut_waveforms_file = { "value": str(mseed.with_suffix(".m").resolve()), "namespace": ns } # Create origin with spline location and set to preferred event origin. origin = Origin() origin.method_id = "spline" origin.longitude = event_info["X"] origin.latitude = event_info["Y"] origin.depth = event_info["Z"] * factor origin.time = UTCDateTime(event_info["DT"]) event.origins = [origin] event.preferred_origin_id = origin.resource_id # Create origin with gaussian location and associate with event origin = Origin() origin.method_id = "gaussian" origin.longitude = event_info["GAU_X"] origin.latitude = event_info["GAU_Y"] origin.depth = event_info["GAU_Z"] * factor origin.time = UTCDateTime(event_info["DT"]) event.origins.append(origin) ouc = OriginUncertainty() ce = ConfidenceEllipsoid() ce.semi_major_axis_length = event_info["COV_ErrY"] * factor ce.semi_intermediate_axis_length = event_info["COV_ErrX"] * factor ce.semi_minor_axis_length = event_info["COV_ErrZ"] * factor ce.major_axis_plunge = 0 ce.major_axis_azimuth = 0 ce.major_axis_rotation = 0 ouc.confidence_ellipsoid = ce ouc.preferred_description = "confidence ellipsoid" # Set uncertainties for both as the gaussian uncertainties for origin in event.origins: origin.longitude_errors.uncertainty = kilometer2degrees( event_info["GAU_ErrX"] * factor / 1e3) origin.latitude_errors.uncertainty = kilometer2degrees( event_info["GAU_ErrY"] * factor / 1e3) origin.depth_errors.uncertainty = event_info["GAU_ErrZ"] * factor origin.origin_uncertainty = ouc # Add OriginQuality info to each origin? for origin in event.origins: origin.origin_type = "hypocenter" origin.evaluation_mode = "automatic" # --- Handle picks file --- pick_file = locate_dir / "picks" / event_uid if pick_file.with_suffix(".picks").is_file(): picks = pd.read_csv(pick_file.with_suffix(".picks")) else: return None for _, pickline in picks.iterrows(): station = str(pickline["Station"]) phase = str(pickline["Phase"]) wid = WaveformStreamID(network_code="", station_code=station) for method in ["modelled", "autopick"]: pick = Pick() pick.extra = AttribDict() pick.waveform_id = wid pick.method_id = method pick.phase_hint = phase if method == "autopick" and str(pickline["PickTime"]) != "-1": pick.time = UTCDateTime(pickline["PickTime"]) pick.time_errors.uncertainty = float(pickline["PickError"]) pick.extra.snr = { "value": float(pickline["SNR"]), "namespace": ns } elif method == "modelled": pick.time = UTCDateTime(pickline["ModelledTime"]) else: continue event.picks.append(pick) # --- Handle amplitudes file --- amps_file = locate_dir / "amplitudes" / event_uid if amps_file.with_suffix(".amps").is_file(): amps = pd.read_csv(amps_file.with_suffix(".amps")) i = 0 for _, ampsline in amps.iterrows(): wid = WaveformStreamID(seed_string=ampsline["id"]) noise_amp = ampsline["Noise_amp"] / 1000 # mm to m for phase in ["P_amp", "S_amp"]: amp = Amplitude() if pd.isna(ampsline[phase]): continue amp.generic_amplitude = ampsline[phase] / 1000 # mm to m amp.generic_amplitude_errors.uncertainty = noise_amp amp.unit = "m" amp.type = "AML" amp.method_id = phase amp.period = 1 / ampsline[f"{phase[0]}_freq"] amp.time_window = TimeWindow( reference=UTCDateTime(ampsline[f"{phase[0]}_time"])) # amp.pick_id = ? amp.waveform_id = wid # amp.filter_id = ? amp.magnitude_hint = "ML" amp.evaluation_mode = "automatic" amp.extra = AttribDict() try: amp.extra.filter_gain = { "value": ampsline[f"{phase[0]}_filter_gain"], "namespace": ns } amp.extra.avg_amp = { "value": ampsline[f"{phase[0]}_avg_amp"] / 1000, # m "namespace": ns } except KeyError: pass if phase[0] == local_mag_ph and not pd.isna(ampsline["ML"]): i += 1 stat_mag = StationMagnitude() stat_mag.extra = AttribDict() # stat_mag.origin_id = ? local_mag_loc stat_mag.mag = ampsline["ML"] stat_mag.mag_errors.uncertainty = ampsline["ML_Err"] stat_mag.station_magnitude_type = "ML" stat_mag.amplitude_id = amp.resource_id stat_mag.extra.picked = { "value": ampsline["is_picked"], "namespace": ns } stat_mag.extra.epi_dist = { "value": ampsline["epi_dist"], "namespace": ns } stat_mag.extra.z_dist = { "value": ampsline["z_dist"], "namespace": ns } event.station_magnitudes.append(stat_mag) event.amplitudes.append(amp) mag = Magnitude() mag.extra = AttribDict() mag.mag = event_info["ML"] mag.mag_errors.uncertainty = event_info["ML_Err"] mag.magnitude_type = "ML" # mag.origin_id = ? mag.station_count = i mag.evaluation_mode = "automatic" mag.extra.r2 = {"value": event_info["ML_r2"], "namespace": ns} event.magnitudes = [mag] event.preferred_magnitude_id = mag.resource_id return event
# Build event object evnt = Event(resource_id='GG_cat_' + str(evnum + 1), creation_info='AU') origin = Origin() origin.time = ev['datetime'] origin.longitude = ev['lon'] origin.latitude = ev['lat'] origin.depth = ev['dep'] evnt.origins.append(origin) mag = Magnitude(creation_info='GG_cat') mag.mag = ev['prefmag'] mag.magnitude_type = ev['prefmagtype'] evnt.magnitudes.append(mag) ''' the time window to request the data will be 20 minutes, check maximum travel time and increase this value accordingly ''' #end_time=start_time+960 # 16 minutes start_time = dt - datetime.timedelta(seconds=60) end_time = dt + datetime.timedelta(seconds=960) # 16 minutes #end_time = dt + datetime.timedelta(seconds=600) # 5 minutes ''' get all waveform data available, use wildcards to reduce the data volume and speedup the process, unfortunately we need to request few times for every number of characters that forms the station name ''' # kluge to fix non-retrieval of data - loop through alphabet integers for ch in range(ord('A'), ord('Z') + 1): print 'Stations beginning with ', chr(ch) st_3 = client.get_waveforms("AU", chr(ch) + "??", "", "[BSEH]?[ENZ]", start_time, end_time)
def request_gcmt(starttime, endtime, minmagnitude=None, mindepth=None, maxdepth=None, minlatitude=None, maxlatitude=None, minlongitude=None, maxlongitude=None): from mechanize import Browser import re """ Description I am using mechanize. My attempt is just preliminary, for the current globalcmt.org site. It is possible to store Moment Tensor information in the catalog file. """ # Split numbers and text r = re.compile("([a-zA-Z]+)([0-9]+)") br = Browser() br.open('http://www.globalcmt.org/CMTsearch.html') # Site has just one form br.select_form(nr=0) br.form['yr'] = str(starttime.year) br.form['mo'] = str(starttime.month) br.form['day'] = str(starttime.day) br.form['oyr'] = str(endtime.year) br.form['omo'] = str(endtime.month) br.form['oday'] = str(endtime.day) br.form['list'] = ['4'] br.form['itype'] = ['ymd'] br.form['otype'] = ['ymd'] if minmagnitude: br.form['lmw'] = str(minmagnitude) if minlatitude: br.form['llat'] = str(minlatitude) if maxlatitude: br.form['ulat'] = str(maxlatitude) if minlongitude: br.form['llon'] = str(minlongitude) if maxlongitude: br.form['ulon'] = str(maxlongitude) if mindepth: br.form['lhd'] = str(mindepth) if maxdepth: br.form['uhd'] = str(maxdepth) print("Submitting parameters to globalcmt.org ") req = br.submit() print("Retrieving data, creating catalog.") data = [] for line in req: data.append(line) data_chunked = _chunking_list(keyword='\n', list=data) origins = [] magnitudes = [] tensor = [] for line in data_chunked: for element in line: if 'event name' in element: try: org = line[1].split() year = int(r.match(org[0]).groups()[1]) mon = int(org[1]) day = int(org[2]) hour = int(org[3]) minute = int(org[4]) sec_temp = int(org[5].split('.')[0]) msec_temp = int(org[5].split('.')[1]) except: org = line[1].split() year = int(org[1]) mon = int(org[2]) day = int(org[3]) hour = int(org[4]) minute = int(org[5]) sec_temp = int(org[6].split('.')[0]) msec_temp = int(org[6].split('.')[1]) origins_temp = UTCDateTime(year, mon, day, hour, minute, sec_temp, msec_temp) # adding time shift located in line[3] origin = origins_temp + float(line[3].split()[2]) magnitude = float(line[1].split()[10]) latitude = float(line[5].split()[1]) longitude = float(line[6].split()[1]) depth = 1000. * float(line[7].split()[1]) m_rr = float(line[8].split()[1]) m_tt = float(line[9].split()[1]) m_pp = float(line[10].split()[1]) m_rt = float(line[11].split()[1]) m_rp = float(line[12].split()[1]) m_tp = float(line[13].split()[1]) magnitudes.append(("Mw", magnitude)) origins.append((latitude, longitude, depth, origin)) tensor.append((m_rr, m_tt, m_pp, m_rt, m_rp, m_tp)) cat = Catalog() for mag, org, ten in zip(magnitudes, origins, tensor): # Create magnitude object. magnitude = Magnitude() magnitude.magnitude_type = mag[0] magnitude.mag = mag[1] # Write origin object. origin = Origin() origin.latitude = org[0] origin.longitude = org[1] origin.depth = org[2] origin.time = org[3] # Create event object and append to catalog object. event = Event() event.magnitudes.append(magnitude) event.origins.append(origin) event.MomentTensor = MomentTensor() event.MomentTensor.m_rr = ten[0] event.MomentTensor.m_tt = ten[1] event.MomentTensor.m_pp = ten[2] event.MomentTensor.m_rt = ten[3] event.MomentTensor.m_rp = ten[4] event.MomentTensor.m_tp = ten[5] cat.append(event) return cat
def _parse_record_e(self, line, event): """ Parses the 'error and magnitude' record E """ orig_time_stderr = self._float(line[2:7]) latitude_stderr = self._float(line[8:14]) longitude_stderr = self._float(line[15:21]) depth_stderr = self._float(line[22:27]) mb_mag = self._float(line[28:31]) mb_nsta = self._int(line[32:35]) ms_mag = self._float(line[36:39]) ms_nsta = self._int(line[39:42]) mag1 = self._float(line[42:45]) mag1_type = line[45:47] mag1_source_code = line[47:51].strip() mag2 = self._float(line[51:54]) mag2_type = line[54:56] mag2_source_code = line[56:60].strip() evid = event.resource_id.id.split('/')[-1] origin = event.origins[0] self._store_uncertainty(origin.time_errors, orig_time_stderr) self._store_uncertainty(origin.latitude_errors, self._lat_err_to_deg(latitude_stderr)) self._store_uncertainty(origin.longitude_errors, self._lon_err_to_deg(longitude_stderr, origin.latitude)) self._store_uncertainty(origin.depth_errors, depth_stderr, scale=1000) if mb_mag is not None: mag = Magnitude() res_id = '/'.join((res_id_prefix, 'magnitude', evid, 'mb')) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id='USGS-NEIC') mag.mag = mb_mag mag.magnitude_type = 'Mb' mag.station_count = mb_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if ms_mag is not None: mag = Magnitude() res_id = '/'.join((res_id_prefix, 'magnitude', evid, 'ms')) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id='USGS-NEIC') mag.mag = ms_mag mag.magnitude_type = 'Ms' mag.station_count = ms_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag1 is not None: mag = Magnitude() mag1_id = mag1_type.lower() res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag1_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag1_source_code) mag.mag = mag1 mag.magnitude_type = mag1_type mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag2 is not None: mag = Magnitude() mag2_id = mag2_type.lower() if mag2_id == mag1_id: mag2_id += '2' res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag2_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag2_source_code) mag.mag = mag2 mag.magnitude_type = mag2_type mag.origin_id = origin.resource_id event.magnitudes.append(mag)
def calculate_moment_magnitudes(cat, output_file): """ :param cat: obspy.core.event.Catalog object. """ Mws = [] Mls = [] Mws_std = [] for event in cat: if not event.origins: print "No origin for event %s" % event.resource_id continue if not event.magnitudes: print "No magnitude for event %s" % event.resource_id continue origin_time = event.origins[0].time local_magnitude = event.magnitudes[0].mag #if local_magnitude < 1.0: #continue moments = [] source_radii = [] corner_frequencies = [] for pick in event.picks: # Only p phase picks. if pick.phase_hint.lower() == "p": radiation_pattern = 0.52 velocity = V_P k = 0.32 elif pick.phase_hint.lower() == "s": radiation_pattern = 0.63 velocity = V_S k = 0.21 else: continue distance = (pick.time - origin_time) * velocity if distance <= 0.0: continue stream = get_corresponding_stream(pick.waveform_id, pick.time, PADDING) if stream is None or len(stream) != 3: continue omegas = [] corner_freqs = [] for trace in stream: # Get the index of the pick. pick_index = int(round((pick.time - trace.stats.starttime) / \ trace.stats.delta)) # Choose date window 0.5 seconds before and 1 second after pick. data_window = trace.data[pick_index - \ int(TIME_BEFORE_PICK * trace.stats.sampling_rate): \ pick_index + int(TIME_AFTER_PICK * trace.stats.sampling_rate)] # Calculate the spectrum. spec, freq = mtspec.mtspec(data_window, trace.stats.delta, 2) try: fit = fit_spectrum(spec, freq, pick.time - origin_time, spec.max(), 10.0) except: continue if fit is None: continue Omega_0, f_c, err, _ = fit Omega_0 = np.sqrt(Omega_0) omegas.append(Omega_0) corner_freqs.append(f_c) M_0 = 4.0 * np.pi * DENSITY * velocity ** 3 * distance * \ np.sqrt(omegas[0] ** 2 + omegas[1] ** 2 + omegas[2] ** 2) / \ radiation_pattern r = 3 * k * V_S / sum(corner_freqs) moments.append(M_0) source_radii.append(r) corner_frequencies.extend(corner_freqs) if not len(moments): print "No moments could be calculated for event %s" % \ event.resource_id.resource_id continue # Calculate the seismic moment via basic statistics. moments = np.array(moments) moment = moments.mean() moment_std = moments.std() corner_frequencies = np.array(corner_frequencies) corner_frequency = corner_frequencies.mean() corner_frequency_std = corner_frequencies.std() # Calculate the source radius. source_radii = np.array(source_radii) source_radius = source_radii.mean() source_radius_std = source_radii.std() # Calculate the stress drop of the event based on the average moment and # source radii. stress_drop = (7 * moment) / (16 * source_radius ** 3) stress_drop_std = np.sqrt((stress_drop ** 2) * \ (((moment_std ** 2) / (moment ** 2)) + \ (9 * source_radius * source_radius_std ** 2))) if source_radius > 0 and source_radius_std < source_radius: print "Source radius:", source_radius, " Std:", source_radius_std print "Stress drop:", stress_drop / 1E5, " Std:", stress_drop_std / 1E5 Mw = 2.0 / 3.0 * (np.log10(moment) - 9.1) Mw_std = 2.0 / 3.0 * moment_std / (moment * np.log(10)) Mws_std.append(Mw_std) Mws.append(Mw) Mls.append(local_magnitude) calc_diff = abs(Mw - local_magnitude) Mw = ("%.3f" % Mw).rjust(7) Ml = ("%.3f" % local_magnitude).rjust(7) diff = ("%.3e" % calc_diff).rjust(7) ret_string = colorama.Fore.GREEN + \ "For event %s: Ml=%s | Mw=%s | " % (event.resource_id.resource_id, Ml, Mw) if calc_diff >= 1.0: ret_string += colorama.Fore.RED ret_string += "Diff=%s" % diff ret_string += colorama.Fore.GREEN ret_string += " | Determined at %i stations" % len(moments) ret_string += colorama.Style.RESET_ALL print ret_string mag = Magnitude() mag.mag = Mw mag.mag_errors.uncertainty = Mw_std mag.magnitude_type = "Mw" mag.origin_id = event.origins[0].resource_id mag.method_id = "Custom fit to Boatwright spectrum" mag.station_count = len(moments) mag.evaluation_mode = "automatic" mag.evaluation_status = "preliminary" mag.comments.append(Comment( \ "Seismic Moment=%e Nm; standard deviation=%e" % (moment, moment_std))) if source_radius > 0 and source_radius_std < source_radius: mag.comments.append(Comment( \ "Source radius=%.2fm; standard deviation=%.2f" % (source_radius, source_radius_std))) event.magnitudes.append(mag) print "Writing output file..." cat.write(output_file, format="quakeml")
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)
def request_gcmt(starttime, endtime, minmagnitude=None, mindepth=None, maxdepth=None, minlatitude=None, maxlatitude=None, minlongitude=None, maxlongitude=None): import mechanize from mechanize import Browser import re """ Description I am using mechanize. My attempt is just preliminary, for the current globalcmt.org site. """ #Split numbers and text r = re.compile("([a-zA-Z]+)([0-9]+)") br = Browser() br.open('http://www.globalcmt.org/CMTsearch.html') #Site has just one form br.select_form(nr=0) br.form['yr'] = str(starttime.year) br.form['mo'] = str(starttime.month) br.form['day'] = str(starttime.day) br.form['oyr'] = str(endtime.year) br.form['omo'] = str(endtime.month) br.form['oday'] = str(endtime.day) br.form['list'] = ['4'] br.form['itype'] = ['ymd'] br.form['otype'] = ['ymd'] if minmagnitude: br.form['lmw'] = str(minmagnitude) if minlatitude : br.form['llat'] = str(minlatitude) if maxlatitude : br.form['ulat'] = str(maxlatitude) if minlongitude: br.form['llon'] = str(minlongitude) if maxlongitude: br.form['ulon'] = str(maxlongitude) if mindepth : br.form['lhd'] = str(mindepth) if maxdepth : br.form['uhd'] = str(maxdepth) print("Submitting parameters to globalcmt.") req = br.submit() print("Retrieving data, creating catalog.") data = [] for line in req: data.append(line) data_chunked = _chunking_list(keyword='\n', list=data) origins = [] magnitudes = [] tensor = [] for line in data_chunked: for element in line: if 'event name' in element: for content in element: org = line[1].split() year = int(r.match(org[0]).groups()[1]) mon = int(org[1]) day = int(org[2]) hour = int(org[3]) minute = int(org[4]) sec_temp = int(org[5].split('.')[0]) msec_temp = int(org[5].split('.')[1]) origins_temp = UTCDateTime(year, mon, day, hour, minute, sec_temp, msec_temp) #adding time shift located in line[3] origin = origins_temp + float(line[3].split()[2]) magnitude = float(line[1].split()[10]) latitude = float(line[5].split()[1]) longitude = float(line[6].split()[1]) depth = 1000. * float(line[7].split()[1]) m_rr = float(line[8].split()[1]) m_tt = float(line[9].split()[1]) m_pp = float(line[10].split()[1]) m_rt = float(line[11].split()[1]) m_rp = float(line[12].split()[1]) m_tp = float(line[13].split()[1]) magnitudes.append( ("Mw", magnitude) ) origins.append( (latitude, longitude, depth, origin) ) tensor.append( (m_rr, m_tt, m_pp, m_rt, m_rp, m_tp) ) cat = Catalog() for mag, org, ten in zip(magnitudes, origins, tensor): # Create magnitude object. magnitude = Magnitude() magnitude.magnitude_type = mag[0] magnitude.mag = mag[1] # Write origin object. origin = Origin() origin.latitude = org[0] origin.longitude = org[1] origin.depth = org[2] origin.time = org[3] # Create event object and append to catalog object. event = Event() event.magnitudes.append(magnitude) event.origins.append(origin) event.MomentTensor = MomentTensor() event.MomentTensor.m_rr = ten[0] event.MomentTensor.m_tt = ten[1] event.MomentTensor.m_pp = ten[2] event.MomentTensor.m_rt = ten[3] event.MomentTensor.m_rp = ten[4] event.MomentTensor.m_tp = ten[5] cat.append(event) return cat
def _parseRecordE(self, line, event): """ Parses the 'error and magnitude' record E """ orig_time_stderr = self._float(line[2:7]) latitude_stderr = self._float(line[8:14]) longitude_stderr = self._float(line[15:21]) depth_stderr = self._float(line[22:27]) mb_mag = self._float(line[28:31]) mb_nsta = self._int(line[32:35]) Ms_mag = self._float(line[36:39]) Ms_nsta = self._int(line[39:42]) mag1 = self._float(line[42:45]) mag1_type = line[45:47] mag1_source_code = line[47:51].strip() mag2 = self._float(line[51:54]) mag2_type = line[54:56] mag2_source_code = line[56:60].strip() evid = event.resource_id.id.split("/")[-1] origin = event.origins[0] self._storeUncertainty(origin.time_errors, orig_time_stderr) self._storeUncertainty(origin.latitude_errors, self._latErrToDeg(latitude_stderr)) self._storeUncertainty(origin.longitude_errors, self._lonErrToDeg(longitude_stderr, origin.latitude)) self._storeUncertainty(origin.depth_errors, depth_stderr, scale=1000) if mb_mag is not None: mag = Magnitude() res_id = "/".join((res_id_prefix, "magnitude", evid, "mb")) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id="USGS-NEIC") mag.mag = mb_mag mag.magnitude_type = "Mb" mag.station_count = mb_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if Ms_mag is not None: mag = Magnitude() res_id = "/".join((res_id_prefix, "magnitude", evid, "ms")) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id="USGS-NEIC") mag.mag = Ms_mag mag.magnitude_type = "Ms" mag.station_count = Ms_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag1 is not None: mag = Magnitude() mag1_id = mag1_type.lower() res_id = "/".join((res_id_prefix, "magnitude", evid, mag1_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag1_source_code) mag.mag = mag1 mag.magnitude_type = mag1_type mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag2 is not None: mag = Magnitude() mag2_id = mag2_type.lower() if mag2_id == mag1_id: mag2_id += "2" res_id = "/".join((res_id_prefix, "magnitude", evid, mag2_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag2_source_code) mag.mag = mag2 mag.magnitude_type = mag2_type mag.origin_id = origin.resource_id event.magnitudes.append(mag)
e = Event() e.event_type = "not existing" o = Origin() o.time = UTCDateTime(2014, 2, 23, 18, 0, 0) o.latitude = 47.6 o.longitude = 12.0 o.depth = 10000 o.depth_type = "operator assigned" o.evaluation_mode = "manual" o.evaluation_status = "preliminary" o.region = FlinnEngdahl().get_region(o.longitude, o.latitude) m = Magnitude() m.mag = 7.2 m.magnitude_type = "Mw" m2 = Magnitude() m2.mag = 7.4 m2.magnitude_type = "Ms" # also included could be: custom picks, amplitude measurements, station magnitudes, # focal mechanisms, moment tensors, ... # make associations, put everything together cat.append(e) e.origins = [o] e.magnitudes = [m, m2] m.origin_id = o.resource_id m2.origin_id = o.resource_id
def calculate_moment_magnitudes(cat, output_file): """ :param cat: obspy.core.event.Catalog object. """ Mws = [] Mls = [] Mws_std = [] for event in cat: if not event.origins: print "No origin for event %s" % event.resource_id continue if not event.magnitudes: print "No magnitude for event %s" % event.resource_id continue origin_time = event.origins[0].time local_magnitude = event.magnitudes[0].mag #if local_magnitude < 1.0: #continue moments = [] source_radii = [] corner_frequencies = [] for pick in event.picks: # Only p phase picks. if pick.phase_hint.lower() == "p": radiation_pattern = 0.52 velocity = V_P k = 0.32 elif pick.phase_hint.lower() == "s": radiation_pattern = 0.63 velocity = V_S k = 0.21 else: continue distance = (pick.time - origin_time) * velocity if distance <= 0.0: continue stream = get_corresponding_stream(pick.waveform_id, pick.time, PADDING) if stream is None or len(stream) != 3: continue omegas = [] corner_freqs = [] for trace in stream: # Get the index of the pick. pick_index = int(round((pick.time - trace.stats.starttime) / \ trace.stats.delta)) # Choose date window 0.5 seconds before and 1 second after pick. data_window = trace.data[pick_index - \ int(TIME_BEFORE_PICK * trace.stats.sampling_rate): \ pick_index + int(TIME_AFTER_PICK * trace.stats.sampling_rate)] # Calculate the spectrum. spec, freq = mtspec.mtspec(data_window, trace.stats.delta, 2) try: fit = fit_spectrum(spec, freq, pick.time - origin_time, spec.max(), 10.0) except: continue if fit is None: continue Omega_0, f_c, err, _ = fit Omega_0 = np.sqrt(Omega_0) omegas.append(Omega_0) corner_freqs.append(f_c) M_0 = 4.0 * np.pi * DENSITY * velocity ** 3 * distance * \ np.sqrt(omegas[0] ** 2 + omegas[1] ** 2 + omegas[2] ** 2) / \ radiation_pattern r = 3 * k * V_S / sum(corner_freqs) moments.append(M_0) source_radii.append(r) corner_frequencies.extend(corner_freqs) if not len(moments): print "No moments could be calculated for event %s" % \ event.resource_id.resource_id continue # Calculate the seismic moment via basic statistics. moments = np.array(moments) moment = moments.mean() moment_std = moments.std() corner_frequencies = np.array(corner_frequencies) corner_frequency = corner_frequencies.mean() corner_frequency_std = corner_frequencies.std() # Calculate the source radius. source_radii = np.array(source_radii) source_radius = source_radii.mean() source_radius_std = source_radii.std() # Calculate the stress drop of the event based on the average moment and # source radii. stress_drop = (7 * moment) / (16 * source_radius ** 3) stress_drop_std = np.sqrt((stress_drop ** 2) * \ (((moment_std ** 2) / (moment ** 2)) + \ (9 * source_radius * source_radius_std ** 2))) if source_radius > 0 and source_radius_std < source_radius: print "Source radius:", source_radius, " Std:", source_radius_std print "Stress drop:", stress_drop / 1E5, " Std:", stress_drop_std / 1E5 Mw = 2.0 / 3.0 * (np.log10(moment) - 9.1) Mw_std = 2.0 / 3.0 * moment_std / (moment * np.log(10)) Mws_std.append(Mw_std) Mws.append(Mw) Mls.append(local_magnitude) calc_diff = abs(Mw - local_magnitude) Mw = ("%.3f" % Mw).rjust(7) Ml = ("%.3f" % local_magnitude).rjust(7) diff = ("%.3e" % calc_diff).rjust(7) ret_string = colorama.Fore.GREEN + \ "For event %s: Ml=%s | Mw=%s | " % (event.resource_id.resource_id, Ml, Mw) if calc_diff >= 1.0: ret_string += colorama.Fore.RED ret_string += "Diff=%s" % diff ret_string += colorama.Fore.GREEN ret_string += " | Determined at %i stations" % len(moments) ret_string += colorama.Style.RESET_ALL print ret_string mag = Magnitude() mag.mag = Mw mag.mag_errors.uncertainty = Mw_std mag.magnitude_type = "Mw" mag.origin_id = event.origins[0].resource_id mag.method_id = "smi:com.github/krischer/moment_magnitude_calculator/automatic/1" mag.station_count = len(moments) mag.evaluation_mode = "automatic" mag.evaluation_status = "preliminary" mag.comments.append(Comment( \ "Seismic Moment=%e Nm; standard deviation=%e" % (moment, moment_std))) mag.comments.append(Comment("Custom fit to Boatwright spectrum")) if source_radius > 0 and source_radius_std < source_radius: mag.comments.append(Comment( \ "Source radius=%.2fm; standard deviation=%.2f" % (source_radius, source_radius_std))) event.magnitudes.append(mag) print "Writing output file..." cat.write(output_file, format="quakeml")
def _parseRecordE(self, line, event): """ Parses the 'error and magnitude' record E """ orig_time_stderr = self._float(line[2:7]) latitude_stderr = self._float(line[8:14]) longitude_stderr = self._float(line[15:21]) depth_stderr = self._float(line[22:27]) mb_mag = self._float(line[28:31]) mb_nsta = self._int(line[32:35]) Ms_mag = self._float(line[36:39]) Ms_nsta = self._int(line[39:42]) mag1 = self._float(line[42:45]) mag1_type = line[45:47] mag1_source_code = line[47:51].strip() mag2 = self._float(line[51:54]) mag2_type = line[54:56] mag2_source_code = line[56:60].strip() evid = event.resource_id.id.split('/')[-1] origin = event.origins[0] self._storeUncertainty(origin.time_errors, orig_time_stderr) self._storeUncertainty(origin.latitude_errors, self._latErrToDeg(latitude_stderr)) self._storeUncertainty( origin.longitude_errors, self._lonErrToDeg(longitude_stderr, origin.latitude)) self._storeUncertainty(origin.depth_errors, depth_stderr, scale=1000) if mb_mag is not None: mag = Magnitude() res_id = '/'.join((res_id_prefix, 'magnitude', evid, 'mb')) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id='USGS-NEIC') mag.mag = mb_mag mag.magnitude_type = 'Mb' mag.station_count = mb_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if Ms_mag is not None: mag = Magnitude() res_id = '/'.join((res_id_prefix, 'magnitude', evid, 'ms')) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id='USGS-NEIC') mag.mag = Ms_mag mag.magnitude_type = 'Ms' mag.station_count = Ms_nsta mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag1 is not None: mag = Magnitude() mag1_id = mag1_type.lower() res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag1_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag1_source_code) mag.mag = mag1 mag.magnitude_type = mag1_type mag.origin_id = origin.resource_id event.magnitudes.append(mag) if mag2 is not None: mag = Magnitude() mag2_id = mag2_type.lower() if mag2_id == mag1_id: mag2_id += '2' res_id = '/'.join((res_id_prefix, 'magnitude', evid, mag2_id)) mag.resource_id = ResourceIdentifier(id=res_id) mag.creation_info = CreationInfo(agency_id=mag2_source_code) mag.mag = mag2 mag.magnitude_type = mag2_type mag.origin_id = origin.resource_id event.magnitudes.append(mag)
def par2quakeml(Par_filename, QuakeML_filename, rotation_axis=[0.0, 1.0, 0.0], rotation_angle=-57.5, origin_time="2000-01-01 00:00:00.0", event_type="other event"): # initialise event ev = Event() # open and read Par file fid = open(Par_filename, 'r') fid.readline() fid.readline() fid.readline() fid.readline() lat_old = 90.0 - float(fid.readline().strip().split()[0]) lon_old = float(fid.readline().strip().split()[0]) depth = float(fid.readline().strip().split()[0]) fid.readline() Mtt_old = float(fid.readline().strip().split()[0]) Mpp_old = float(fid.readline().strip().split()[0]) Mrr_old = float(fid.readline().strip().split()[0]) Mtp_old = float(fid.readline().strip().split()[0]) Mtr_old = float(fid.readline().strip().split()[0]) Mpr_old = float(fid.readline().strip().split()[0]) # rotate event into physical domain lat, lon = rot.rotate_lat_lon(lat_old, lon_old, rotation_axis, rotation_angle) Mrr, Mtt, Mpp, Mtr, Mpr, Mtp = rot.rotate_moment_tensor( Mrr_old, Mtt_old, Mpp_old, Mtr_old, Mpr_old, Mtp_old, lat_old, lon_old, rotation_axis, rotation_angle) # populate event origin data ev.event_type = event_type ev_origin = Origin() ev_origin.time = UTCDateTime(origin_time) ev_origin.latitude = lat ev_origin.longitude = lon ev_origin.depth = depth ev.origins.append(ev_origin) # populte event moment tensor ev_tensor = Tensor() ev_tensor.m_rr = Mrr ev_tensor.m_tt = Mtt ev_tensor.m_pp = Mpp ev_tensor.m_rt = Mtr ev_tensor.m_rp = Mpr ev_tensor.m_tp = Mtp ev_momenttensor = MomentTensor() ev_momenttensor.tensor = ev_tensor ev_momenttensor.scalar_moment = np.sqrt(Mrr ** 2 + Mtt ** 2 + Mpp ** 2 + Mtr ** 2 + Mpr ** 2 + Mtp ** 2) ev_focalmechanism = FocalMechanism() ev_focalmechanism.moment_tensor = ev_momenttensor ev_focalmechanism.nodal_planes = NodalPlanes().setdefault(0, 0) ev.focal_mechanisms.append(ev_focalmechanism) # populate event magnitude ev_magnitude = Magnitude() ev_magnitude.mag = 0.667 * (np.log10(ev_momenttensor.scalar_moment) - 9.1) ev_magnitude.magnitude_type = 'Mw' ev.magnitudes.append(ev_magnitude) # write QuakeML file cat = Catalog() cat.append(ev) cat.write(QuakeML_filename, format="quakeml") # clean up fid.close()
eid = line_elements[-1] otime = uh.eid2otime(eid) elon = line_elements[6] elat = line_elements[7] edep = float(line_elements[8]) * 1000.0 # meters emag = line_elements[16] # create event object orig = Origin() orig.longitude = elon orig.latitude = elat orig.depth = edep orig.time = otime mag = Magnitude() mag.mag = emag mag.magnitude_type = "Mw" ev = Event() ev.origins.append(orig) ev.magnitudes.append(mag) if send_request: # get waveforms client = Client("IRIS") getwaveform_iris.run_get_waveform(c=client, event=ev, min_dist=min_dist, max_dist=max_dist, before=tbefore_sec, after=tafter_sec, network=network, station=station,
def getwf_iris_ncedc_llnl(origin0, client_pick): print("Running function getwf_iris_ncedc_llnl") # parameters for waveform request tbefore_sec = 100 tafter_sec = 600 # DEFAULT SETTINGS (see getwaveform_iris.py) rotateRTZ = True rotateUVW = False # works only if 'rotateRTZ = True' output_cap_weight_file = True detrend = True demean = True output_event_info = True taper = False ifplot_spectrogram = False # for CAP all waveforms need to have the same sample rate resample_TF = True resample_freq = 20.0 # 0 for no resampling scale_factor = 10**2 # for CAP use 10**2 (to convert m/s to cm/s) # event parameters sec_before_after_event = 10 # time window to search for a target event in a catalog min_dist = 0 max_dist = 1200 # station parameters # 20170321 [email protected] -- I disabled retrieving data for the # networks listed below # reason 1 some are dense/local and don't improve station coverage # reason 2 many have crappy data (noisy) # reason 3 some have very large amplitudes. Bad response? network = '*,-XK,-XM,-XS,-XC,-XU,-XT,-XE' station = '*,-PURD,-NV33,-GPO' # all stations channel = 'BH?,LH?' overwrite_ddir = 1 # 1 = delete data directory if it already exists icreateNull = 0 # create Null traces so that rotation can work (obsby stream.rotate require 3 traces) # filter # set ipre_filt = 0 to prevent extra filtering ifFilter = False filter_type = 'bandpass' # LLNL filter 10-50 sec is most stable. Some waveforms >= 100 sec show # oscillations. Use factor of 2 limit = 200 sec for prefilter f1 = 1 / 200 f2 = 1 / 10 zerophase = True # False = causal, True = acausal corners = 4 # Is corner in Obspy same as Pole in SAC? remove_response = True iplot_response = False ipre_filt = 2 # 0 No pre_filter # 1 default pre_filter (see getwaveform_iris.py) # 2 user-defined pre_filter f0 = 0.5 * f1 f3 = 2.0 * f2 # The following are for the FMTU paper f0 = 0.005 f1 = 0.006 f3 = 10 f4 = 15 pre_filt = (f0, f1, f2, f3) # applies for ipre_filt = 2 only # NOTE event data from user-defined catalog! # initialize objects ev = Event() org = Origin() mag = Magnitude() # build objects org.time = UTCDateTime(origin0[0]) org.longitude = origin0[1] org.latitude = origin0[2] org.depth = origin0[3] mag.mag = origin0[5] mag.magnitude_type = origin0[6] # Mw, ml, mb, ... ev.origins.append(org) ev.magnitudes.append(mag) # Delete existing data directory eid = util_helpers.otime2eid(ev.origins[0].time) ddir = './' + eid if os.path.exists('RAW'): print("WARNING. %s already exists. Deleting ..." % ddir) shutil.rmtree('RAW') if overwrite_ddir and os.path.exists(ddir): print("WARNING. %s already exists. Deleting ..." % ddir) shutil.rmtree(ddir) if client_pick is "IRIS": print('Using client %s' % client_pick) idb = 1 client_list = ["IRIS", "NCEDC"] print("WARNING using event data from user-defined catalog") # LLNL if client_pick is "LLNL": print('Using client %s' % client_pick) idb = 3 client_list = ["LLNL"] client = llnl_db_client.LLNLDBClient( "/store/raw/LLNL/UCRL-MI-222502/westernus.wfdisc") # get event time and event ID otime = obspy.UTCDateTime(origin0[0]) cat = client.get_catalog() mintime_str = "time > %s" % (otime - sec_before_after_event) maxtime_str = "time < %s" % (otime + sec_before_after_event) print(mintime_str + "\n" + maxtime_str) ev = cat.filter(mintime_str, maxtime_str) nev = len(ev) if nev == 1: ev = ev[0] # doesn't have magnitude (ATRISCO) elif nev > 1: ev = ev[1] # [0] may not include magnitude. [1] may (LLNL) else: print("No events in the catalog for the given time period. Stop.") # The IRIS requests include BK data, but it has to be requested through # the NCEDC client for iclient in client_list: if iclient is "IRIS": network = network client = Client(iclient) elif iclient is "NCEDC": network = 'BK' station = '*' # doesn't like "-staX" client = Client(iclient) try: gw.run_get_waveform(c=client, event=ev, idb=idb, ref_time_place=ev, min_dist=min_dist, max_dist=max_dist, before=tbefore_sec, after=tafter_sec, network=network, station=station, channel=channel, resample_freq=resample_freq, ifrotateRTZ=rotateRTZ, ifrotateUVW=rotateUVW, ifCapInp=output_cap_weight_file, ifRemoveResponse=remove_response, ifDetrend=detrend, ifDemean=demean, Taper=taper, ifEvInfo=output_event_info, scale_factor=scale_factor, icreateNull=icreateNull, ipre_filt=ipre_filt, pre_filt=pre_filt, ifFilter=ifFilter, fmin=f1, fmax=f2, filter_type=filter_type, zerophase=zerophase, corners=corners, iplot_response=iplot_response, ifplot_spectrogram=ifplot_spectrogram) except: print("~~~~~ SOMETHING HAPPENED ~~~~~~~~~~") print(ev, client) print("Continuing") continue
def test_creating_minimal_quakeml_with_mt(self): """ Tests the creation of a minimal QuakeML containing origin, magnitude and moment tensor. """ # Rotate into physical domain lat, lon, depth, org_time = 10.0, -20.0, 12000, UTCDateTime(2012, 1, 1) mrr, mtt, mpp, mtr, mpr, mtp = 1E18, 2E18, 3E18, 3E18, 2E18, 1E18 scalar_moment = math.sqrt( mrr ** 2 + mtt ** 2 + mpp ** 2 + mtr ** 2 + mpr ** 2 + mtp ** 2) moment_magnitude = 0.667 * (math.log10(scalar_moment) - 9.1) # Initialise event ev = Event(event_type="earthquake") ev_origin = Origin(time=org_time, latitude=lat, longitude=lon, depth=depth, resource_id=ResourceIdentifier()) ev.origins.append(ev_origin) # populate event moment tensor ev_tensor = Tensor(m_rr=mrr, m_tt=mtt, m_pp=mpp, m_rt=mtr, m_rp=mpr, m_tp=mtp) ev_momenttensor = MomentTensor(tensor=ev_tensor) ev_momenttensor.scalar_moment = scalar_moment ev_momenttensor.derived_origin_id = ev_origin.resource_id ev_focalmechanism = FocalMechanism(moment_tensor=ev_momenttensor) ev.focal_mechanisms.append(ev_focalmechanism) # populate event magnitude ev_magnitude = Magnitude() ev_magnitude.mag = moment_magnitude ev_magnitude.magnitude_type = 'Mw' ev_magnitude.evaluation_mode = 'automatic' ev.magnitudes.append(ev_magnitude) # write QuakeML file cat = Catalog(events=[ev]) memfile = io.BytesIO() cat.write(memfile, format="quakeml", validate=IS_RECENT_LXML) memfile.seek(0, 0) new_cat = _read_quakeml(memfile) self.assertEqual(len(new_cat), 1) event = new_cat[0] self.assertEqual(len(event.origins), 1) self.assertEqual(len(event.magnitudes), 1) self.assertEqual(len(event.focal_mechanisms), 1) org = event.origins[0] mag = event.magnitudes[0] fm = event.focal_mechanisms[0] self.assertEqual(org.latitude, lat) self.assertEqual(org.longitude, lon) self.assertEqual(org.depth, depth) self.assertEqual(org.time, org_time) # Moment tensor. mt = fm.moment_tensor.tensor self.assertTrue((fm.moment_tensor.scalar_moment - scalar_moment) / scalar_moment < scalar_moment * 1E-10) self.assertEqual(mt.m_rr, mrr) self.assertEqual(mt.m_pp, mpp) self.assertEqual(mt.m_tt, mtt) self.assertEqual(mt.m_rt, mtr) self.assertEqual(mt.m_rp, mpr) self.assertEqual(mt.m_tp, mtp) # Mag self.assertAlmostEqual(mag.mag, moment_magnitude) self.assertEqual(mag.magnitude_type, "Mw") self.assertEqual(mag.evaluation_mode, "automatic")
def iris2quakeml(url, output_folder=None): if not "/spudservice/" in url: url = url.replace("/spud/", "/spudservice/") if url.endswith("/"): url += "quakeml" else: url += "/quakeml" print "Downloading %s..." % url r = requests.get(url) if r.status_code != 200: msg = "Error Downloading file!" raise Exception(msg) # For some reason the quakeml file is escaped HTML. h = HTMLParser.HTMLParser() data = h.unescape(r.content) # Replace some XML tags. data = data.replace("long-period body waves", "body waves") data = data.replace("intermediate-period surface waves", "surface waves") data = data.replace("long-period mantle waves", "mantle waves") data = data.replace("<html><body><pre>", "") data = data.replace("</pre></body></html>", "") # Change the resource identifiers. Colons are not allowed in QuakeML. pattern = r"(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{6})" data = re.sub(pattern, r"\1-\2-\3T\4-\5-\6.\7", data) data = StringIO(data) try: cat = readEvents(data) except: msg = "Could not read downloaded event data" raise ValueError(msg) # Parse the event, and use only one origin, magnitude and focal mechanism. # Only the first event is used. Should not be a problem for the chosen # global cmt application. ev = cat[0] if ev.preferred_origin(): ev.origins = [ev.preferred_origin()] else: ev.origins = [ev.origins[0]] if ev.preferred_focal_mechanism(): ev.focal_mechanisms = [ev.preferred_focal_mechanism()] else: ev.focal_mechanisms = [ev.focal_mechanisms[0]] try: mt = ev.focal_mechanisms[0].moment_tensor except: msg = "No moment tensor found in file." raise ValueError seismic_moment_in_dyn_cm = mt.scalar_moment if not seismic_moment_in_dyn_cm: msg = "No scalar moment found in file." raise ValueError(msg) # Create a new magnitude object with the moment magnitude calculated from # the given seismic moment. mag = Magnitude() mag.magnitude_type = "Mw" mag.origin_id = ev.origins[0].resource_id # This is the formula given on the GCMT homepage. mag.mag = (2.0 / 3.0) * (math.log10(seismic_moment_in_dyn_cm) - 16.1) mag.resource_id = ev.origins[0].resource_id.resource_id.replace( "Origin", "Magnitude") ev.magnitudes = [mag] ev.preferred_magnitude_id = mag.resource_id # Convert the depth to meters. org = ev.origins[0] org.depth *= 1000.0 if org.depth_errors.uncertainty: org.depth_errors.uncertainty *= 1000.0 # Ugly asserts -- this is just a simple script. assert (len(ev.magnitudes) == 1) assert (len(ev.origins) == 1) assert (len(ev.focal_mechanisms) == 1) # All values given in the QuakeML file are given in dyne * cm. Convert them # to N * m. for key, value in mt.tensor.iteritems(): if key.startswith("m_") and len(key) == 4: mt.tensor[key] /= 1E7 if key.endswith("_errors") and hasattr(value, "uncertainty"): mt.tensor[key].uncertainty /= 1E7 mt.scalar_moment /= 1E7 if mt.scalar_moment_errors.uncertainty: mt.scalar_moment_errors.uncertainty /= 1E7 p_axes = ev.focal_mechanisms[0].principal_axes for ax in [p_axes.t_axis, p_axes.p_axis, p_axes.n_axis]: if ax is None or not ax.length: continue ax.length /= 1E7 # Check if it has a source time function stf = mt.source_time_function if stf: if stf.type != "triangle": msg = ("Source time function type '%s' not yet mapped. Please " "contact the developers.") % stf.type raise NotImplementedError(msg) if not stf.duration: if not stf.decay_time: msg = "Not known how to derive duration without decay time." raise NotImplementedError(msg) # Approximate the duraction for triangular STF. stf.duration = 2 * stf.decay_time # Get the flinn_engdahl region for a nice name. fe = FlinnEngdahl() region_name = fe.get_region(ev.origins[0].longitude, ev.origins[0].latitude) region_name = region_name.replace(" ", "_") event_name = "GCMT_event_%s_Mag_%.1f_%s-%s-%s-%s-%s.xml" % \ (region_name, ev.magnitudes[0].mag, ev.origins[0].time.year, ev.origins[0].time.month, ev.origins[0].time.day, ev.origins[0].time.hour, ev.origins[0].time.minute) # Check if the ids of the magnitude and origin contain the corresponding # tag. Otherwise replace tme. ev.origins[0].resource_id = ev.origins[0].resource_id.resource_id.replace( "quakeml/gcmtid", "quakeml/origin/gcmtid") ev.magnitudes[0].resource_id = \ ev.magnitudes[0].resource_id.resource_id.replace( "quakeml/gcmtid", "quakeml/magnitude/gcmtid") # Fix up the moment tensor resource_ids. mt.derived_origin_id = ev.origins[0].resource_id mt.resource_id = mt.resource_id.resource_id.replace( "focalmechanism", "momenttensor") cat = Catalog() cat.resource_id = ev.origins[0].resource_id.resource_id.replace( "origin", "event_parameters") cat.append(ev) if output_folder: event_name = os.path.join(output_folder, event_name) cat.write(event_name, format="quakeml", validate=True) print "Written file", event_name