#!/usr/bin/python3 #script to calculate a MLv (Magnitude Local,Vertical) earthquake magnitude using Geoscience Australia's WEST/EAST/SOUTH metric import numpy as np from scipy.signal import welch import obspy,math,sys from obspy.geodetics import gps2dist_azimuth from obspy import read, Stream, UTCDateTime,read_events from obspy.core.event import Origin from obspy.taup import TauPyModel from obspy.clients.fdsn import Client from obspy.signal.invsim import estimate_wood_anderson_amplitude_using_response ######################### DEFINE AN EARTHQUAKE #sept 21 2021 victoria Mw 5.9 event_lat=-37.486 event_long=146.347 event_depth=12.0 t=obspy.UTCDateTime('2021-09-21T23:15:53.617000Z') region ="EAST" #can also be WEST or SOUTH (strictly Eyre Basin) searchdist = 5 #distance in degrees from the event to add stations #code to determine the maximum PSD frequency / time between peaks (for use in estimate_wood_anderson) def get_peakpeak_time_psd(tr): peak = np.argmax(tr.data) data = tr.data[peak-100:peak+100] f,psd = welch(data,nperseg=64,fs=tr.stats.sampling_rate,nfft=64) f = f[2:]; psd=psd[2:] #avoid 0 maxfreq = f[np.argmax(psd)] timespan = 1/(2*maxfreq) return timespan #https://github.com/GeoscienceAustralia/ga-mla def GA_mag(ampl_mm,dist_km,region='WEST'): if region.upper() == "SOUTH": mag = math.log10(ampl_mm) + 1.1*math.log10(dist_km) + 0.0013*dist_km + 0.7 elif region.upper() == "EAST": mag = math.log10(ampl_mm) + (1.34*math.log10(dist_km/100)) + (0.00055 * (dist_km - 100)) + 3.13 else: mag = math.log10(ampl_mm) + 1.137*math.log10(dist_km) + 0.000657*dist_km + 0.66 return mag ################################### set velocity model (not too important) and data centers model = TauPyModel(model="iasp91") iris = Client("IRIS") auspass=Client('AUSPASS') ################# #collect all station inventory within ~5 degrees of event iris_inv = iris.get_stations(network='AU',latitude=event_lat,longitude=event_long,maxradius=searchdist,channel='BHZ',startbefore=t,endafter=t,level='response') #only Z channel for now auspass_inv = auspass.get_stations(network='*',latitude=event_lat,longitude=event_long,maxradius=searchdist,channel='H*Z',startbefore=t,endafter=t,level='response') inv = iris_inv.copy(); inv += auspass_inv data = [] #go through the inventory, pull waveforms, calculate magnitude, store results for nslc in inv.get_contents()['channels']: n,s,l,c = nslc.split('.') if n=="S1" and c[0] == "B": continue #skip the 10hz data sta_lat,sta_lon = inv.get_coordinates(nslc)['latitude'], inv.get_coordinates(nslc)['longitude'] epi_dist, az, baz = gps2dist_azimuth(float(event_lat),float(event_long), sta_lat, sta_lon) epi_dist_km = epi_dist / 1000 arrivals=model.get_travel_times(source_depth_in_km=float(event_depth),distance_in_degree=epi_dist_km/(111.19*math.cos(sta_lat*np.pi/180)),phase_list=['ttbasic']) p_arrival = t+ arrivals[0].time if nslc in iris_inv.get_contents()['channels']: try: st = iris.get_waveforms(n,s,l,c,starttime=t-10,endtime=t+120) except: print(" ! no data for %s" % nslc) continue elif nslc in auspass_inv.get_contents()['channels']: try: st = auspass.get_waveforms(n,s,l,c,starttime=t-10,endtime=t+120) except: print(" ! no data for %s" % nslc) continue st.detrend("demean"); st.detrend("linear") st.filter('bandpass', freqmin=1, freqmax=10) st.taper(0.05,type='hann', max_length=2, side='left') st.merge(fill_value=0) tr_z= st.select(component="Z")[0] peakpeakamp = 2*max(abs(tr_z.data)) peakpeaktime = get_peakpeak_time_psd(tr_z) response = inv.get_response(nslc,t) ampl_z = estimate_wood_anderson_amplitude_using_response(response,peakpeakamp,peakpeaktime) #returns amplitude in mm r = math.sqrt(float(event_depth)**2+epi_dist_km**2) mag = GA_mag(ampl_z,r,region) data.append([nslc,ampl_z,epi_dist_km,mag]) print("%s success! mag %.2f (distance = %.2fkm)" % (nslc,mag,epi_dist_km)) amplitudes = [ele[1] for ele in data] mags = [ele[3] for ele in data] print("\n>>> average magnitude= %.2f (std %.2f)" % (np.mean(mags),np.std(mags)))