def create_orthoganality_examples(N, E, angles): """Create examples where the second horizontal component is rotated out of orthoganality by the amount of degrees specified. The angle is the angle difference between the two components holding component 1 fixed.""" for angle in angles: # We add 180 because the angle is back azimuth. The rotation does not allow # negative angles so we continue on around the other way. rot_angle = 180 + angle - 90. if rot_angle < 0.: r, t = rotate.rotate_ne_rt(N[0].data, E[0].data, (360. + rot_angle)) elif rot_angle > 360.: r, t = rotate.rotate_ne_rt(N[0].data, E[0].data, (rot_angle - 360.)) else: r, t = rotate.rotate_ne_rt(N[0].data, E[0].data, rot_angle) dir = "orthogonality/%03d" % (angle) try: os.mkdir(dir) except: # Directory exists do nothing pass tr_e = E[0].copy() tr_e.data = t.astype('int32') N[0].write("%s/%s" % (dir, N[0].id), format='MSEED') tr_e.write("%s/%s" % (dir, tr_e.id), format='MSEED')
def rotateToGCP(tr): #begin loop over data stream for i in range(len(tr)-1): # split channel li0 = list(tr[i+0].stats['channel']) li1 = list(tr[i+1].stats['channel']) # chech if station and part 1 of channel is identical and location if li0[0] == li1[0] and li0[1] == li1[1] \ and tr[i+0].stats['station'] == tr[i+1].stats['station']\ and tr[i+0].stats['location'] == tr[i+1].stats['location']: rch = li0[0] + li0[1] + 'R' tch = li0[0] + li0[1] + 'T' # if yes 3 possibility: EN, NE , pass if li0[2]=="E" and li1[2]=="N": #baz baz = tr[i].stats['baz'] if tr[i+0].stats['npts'] == tr[i+1].stats['npts']: # rotate 0-1 (tr[i+1].data,tr[i+0].data) = rotate_ne_rt(tr[i+1].data,tr[i+0].data,baz) tr[i+0].stats['channel']=tch tr[i+1].stats['channel']=rch i=i+1 else: print "Can't rotate ",tr[i+0].stats['station'],tr[i+0].stats['channel'], " and ", \ tr[i+1].stats['station'],tr[i+1].stats['channel'] elif li0[2]=="N" and li1[2]=="E": #baz baz = tr[i].stats['baz'] if tr[i+0].stats['npts'] == tr[i+1].stats['npts']: # # rotate 1-0 (tr[i+0].data,tr[i+1].data) = rotate_ne_rt(tr[i+0].data,tr[i+1].baz) tr[i+1].stats['channel']=tch tr[i+0].stats['channel']=rch i=i+1 else: print "Can't rotate ",tr[i+0].stats['station'],tr[i+0].stats['channel'], " and ", \ tr[i+1].stats['station'],tr[i+1].stats['channel'] else: pass return tr
def test_rotate2zne_against_ne_rt_picking_any_two_horizontal_comps(self): """ This also tests non-orthogonal configurations to some degree. """ np.random.seed(456) z = np.random.random(10) n = np.random.random(10) e = np.random.random(10) # Careful to not pick any coordinate axes. for ba in [14.325, 38.234, 78.1, 136.3435, 265.4, 351.35]: r, t = rotate_ne_rt(n=n, e=e, ba=ba) _r = [r, ba + 180, 0] _t = [t, ba + 270, 0] _n = [n, 0, 0] _e = [e, 90, 0] # Picking any two should be enough to reconstruct n and e. for a, b in itertools.permutations([_r, _t, _n, _e], 2): z_new, n_new, e_new = rotate2zne(z, 0, -90, a[0], a[1], a[2], b[0], b[1], b[2]) np.testing.assert_allclose(z_new, z) np.testing.assert_allclose(n_new, n) np.testing.assert_allclose(e_new, e)
def azimuth_check(stack, st, debug=True): # stack is in the radial direction # for each R and T results = {} stas = list(set([tr.stats.station for tr in st])) for sta in stas: st_sta = st.select(station=sta) best_val = -100. for ang in range(-30, 30, 1): ang = float(ang) print(ang) st2 = st_sta.copy() # rotate R.data, T.data = rotate_ne_rt( st2.select(component='R')[0].data, st2.select(component='T')[0].data, ang) cc = correlation(st2[0].data, stack, 20) shift, value = xcorr_max(cc) if np.abs(value) > best_val: best_val = value best_ang = ang results[sta] = [best_val, best_ang] print(results) return results
def test_rotate_ne_rt_vs_pitsa(self): """ Test horizontal component rotation against PITSA. """ # load test files with gzip.open(os.path.join(self.path, 'rjob_20051006_n.gz')) as f: data_n = np.loadtxt(f) with gzip.open(os.path.join(self.path, 'rjob_20051006_e.gz')) as f: data_e = np.loadtxt(f) # test different angles, one from each sector for angle in [30, 115, 185, 305]: # rotate traces datcorr_r, datcorr_t = rotate_ne_rt(data_n, data_e, angle) # load pitsa files with gzip.open(os.path.join(self.path, 'rjob_20051006_r_%sdeg.gz' % angle)) as f: data_pitsa_r = np.loadtxt(f) with gzip.open(os.path.join(self.path, 'rjob_20051006_t_%sdeg.gz' % angle)) as f: data_pitsa_t = np.loadtxt(f) # Assert. self.assertTrue(np.allclose(datcorr_r, data_pitsa_r, rtol=1E-3, atol=1E-5)) self.assertTrue(np.allclose(datcorr_t, data_pitsa_t, rtol=1E-3, atol=1E-5))
def rotater(tr, inv, evlo, evla): lat = inv[0][0].latitude lon = inv[0][0].longitude dist, baz, _ = gps2dist_azimuth(lat, lon, evla, evlo) e = rotate_ne_rt(tr[0].data, tr[1].data, baz) tmptr = tr.copy() tmptr[0].data = e[0] tmptr[1].data = e[1] return tmptr, lat, lon, dist
def procGUI(self): # get stream st = self.stn.stream self.resp = self.stn.response # get selected channels chn_filter = self.chn[0:2] st = st.select(channel="{:}*".format(chn_filter)) # Shorten time range of stream to times given st = st.trim(starttime=UTCDateTime(self.lside), endtime=UTCDateTime(self.rside)) STEP_DEG = 1 ba_list = np.arange(0, 360, STEP_DEG) r_max = [] t_max = [] ba_max = [] for ba in ba_list: z = st.select(channel="**Z")[0] n = st.select(channel="**N")[0] e = st.select(channel="**E")[0] # filter traces z, times = procTrace(z, ref_datetime=self.ref_datetime, resp=self.resp, bandpass=[2, 8]) n, _ = procTrace(n, ref_datetime=self.ref_datetime, resp=self.resp, bandpass=[2, 8]) e, _ = procTrace(e, ref_datetime=self.ref_datetime, resp=self.resp, bandpass=[2, 8]) z = z[0] n = n[0] e = e[0] times = times[0] r, t = rotate_ne_rt(n, e, ba) # a = st.rotate('NE->RT', back_azimuth=ba) # print(a[0].stats.back_azimuth) print("Current Back-Azimuth = {:} deg | RAD = {:.2f} | TRN = {:.2f}".format(ba, np.max(r), np.max(t))) ba_max.append(ba) r_max.append(np.max(r)) t_max.append(np.max(t)) self.zne_canvas[0].plot(x=times, y=z, update=True, clear=True) self.zne_canvas[1].plot(x=times, y=r, update=True, clear=True) self.zne_canvas[2].plot(x=times, y=t, update=True, clear=True) rad = pg.PlotCurveItem(ba_max, r_max, pen=pg.mkPen(color=(255, 0, 0))) trn = pg.PlotCurveItem(ba_max, t_max, pen=pg.mkPen(color=(0, 0, 255))) self.backaz_canvas.addItem(rad, update=True, clear=True, name="Radial") self.backaz_canvas.addItem(trn, update=True, clear=True, name="Transverse") self.backaz_canvas.setLabel('left', "Positive Maximum Amplitude (Radial)") self.backaz_canvas.setLabel('bottom', "Back-Azimuth [deg]") # self.backaz_canvas.plot(x=ba_max, y=t_max, update=True, clear=True, name="Transverse", pen=pg.mkPen(color=(0, 0, 255))) pg.QtGui.QApplication.processEvents()
def test_SKS(): import matplotlib matplotlib.use('Agg') import numpy as np from obspy.core import Stream from obspy.signal.rotate import rotate_ne_rt from telewavesim import utils as ut from telewavesim import wiggle as wg modfile = resource_filename('telewavesim', 'examples/models/model_SKS.txt') wvtype = 'SV' npts = 3000 # Number of samples dt = 0.05 # Sample distance in seconds slow = 0.04 # Horizontal slowness (or ray parameter) in s/km baz = np.arange(0., 360., 10.) model = ut.read_model(modfile) t1 = ut.calc_ttime(model, slow, wvtype=wvtype) assert round(t1, 1) == 21.6 trR = Stream() trT = Stream() # Loop over range of data for bb in baz: # Calculate the plane wave seismograms trxyz = ut.run_plane(model, slow, npts, dt, bb, wvtype=wvtype) # Extract East, North and Vertical ntr = trxyz[0] etr = trxyz[1] ztr = trxyz[2] # Copy to radial and transverse rtr = ntr.copy() ttr = etr.copy() # Rotate to radial and transverse rtr.data, ttr.data = rotate_ne_rt(ntr.data, etr.data, bb) # Append to streams trR.append(rtr) trT.append(ttr) # Set frequency corners in Hz f1 = 0.01 f2 = 0.2 # Filter to get wave-like traces trR.filter('bandpass', freqmin=f1, freqmax=f2, corners=2, zerophase=True) trT.filter('bandpass', freqmin=f1, freqmax=f2, corners=2, zerophase=True) # Plot as wiggles with tempfile.TemporaryDirectory() as tempdir: wg.pw_wiggles_baz(trR, trT, 'test', btyp='baz', scale=0.05, t1=t1, tmin=0., tmax=40, save=True, ftitle=join(tempdir, 'sks'), wvtype='SV')
def rotate_trace_to_zrt(str1): """ This function rotates a stream object (either in ENZ or 12Z) in to a stream object of TRZ """ for k, tr in enumerate(str1): if tr.stats.channel[2] == 'Z': tr_z = tr elif tr.stats.channel[2] == 'E' or tr.stats.channel[2] == '1': tr_e = tr elif tr.stats.channel[2] == 'N' or tr.stats.channel[2] == '2': tr_n = tr else: sys.exit('Problem with ' + tr.stats.channel) if 'tr_e' not in vars(): sys.exit('No east component') else: tr_r = tr_e.copy() if 'tr_n' not in vars(): sys.exit('No north component') else: tr_t = tr_n.copy() if 'tr_z' not in vars(): sys.exit('No vertical component') else: tr_z2 = tr_z.copy() # note that even traces labelled as E or N in the channel name may not have the right cmpaz. (tr_z2.data, tr_n.data, tr_e.data) = rotate2zne(tr_z.data, tr_z.stats.cmpaz, tr_z.stats.dip, tr_n.data, tr_n.stats.cmpaz, tr_n.stats.dip, tr_e.data, tr_e.stats.cmpaz, tr_e.stats.dip) baz = tr_z2.stats.back_azimuth #baz=19.29817039741116 vs baz_sac= 1.937192e+01 # the baz in sac is not accurate enough that could cause discrepancy with the rotation results # what is in rotate_ne_to_tr (confirmed) # ba = radians(ba) #r = - e * sin(ba) - n * cos(ba) #t = - e * cos(ba) + n * sin(ba) (tr_r.data, tr_t.data) = rotate_ne_rt(tr_n.data, tr_e.data, baz) # after rotation, inclination is not changed but azimuth is changed (tr_r.stats.cmpinc, tr_t.stats.cmpinc) = (90, 90) (tr_r.stats.cmpaz, tr_t.stats.cmpaz) = ((baz + 180) % 360., (baz + 270) % 360.) (tr_r.stats.channel, tr_t.stats.channel) = (tr_r.stats.channel[0:2] + 'R', tr_t.stats.channel[0:2] + 'T') str2 = Stream(traces=[tr_t, tr_r, tr_z2]) return str2
def test_rotate2zne_against_rotate_ne_rt(self): np.random.seed(123) z = np.random.random(10) n = np.random.random(10) e = np.random.random(10) for ba in [0.0, 14.325, 38.234, 78.1, 90.0, 136.3435, 265.4, 351.35]: r, t = rotate_ne_rt(n=n, e=e, ba=ba) # Unrotate with rotate2zne() - this should make sure the azimuth is # interpreted correctly. z_new, n_new, e_new = rotate2zne(z, 0, -90, r, ba + 180, 0, t, ba + 270, 0) np.testing.assert_allclose(z_new, z) np.testing.assert_allclose(n_new, n) np.testing.assert_allclose(e_new, e)
def test_rotate_ne_rt_ne(self): """ Rotating there and back with the same back-azimuth should not change the data. """ # load the data with gzip.open(os.path.join(self.path, 'rjob_20051006_n.gz')) as f: data_n = np.loadtxt(f) with gzip.open(os.path.join(self.path, 'rjob_20051006_e.gz')) as f: data_e = np.loadtxt(f) # Use double precision to get more accuracy for testing. data_n = np.require(data_n, np.float64) data_e = np.require(data_e, np.float64) ba = 33.3 new_n, new_e = rotate_ne_rt(data_n, data_e, ba) new_n, new_e = rotate_rt_ne(new_n, new_e, ba) self.assertTrue(np.allclose(data_n, new_n, rtol=1E-7, atol=1E-12)) self.assertTrue(np.allclose(data_e, new_e, rtol=1E-7, atol=1E-12))
def test_Audet2016(): import matplotlib matplotlib.use('Agg') from obspy.core import Stream from obspy.signal.rotate import rotate_ne_rt from telewavesim import utils as ut from telewavesim import wiggle as wg modfile = resource_filename('telewavesim', 'examples/models/model_Audet2016.txt') wvtype = 'P' npts = 3000 # Number of samples dt = 0.01 # Sample distance in seconds dp = 2000. # Deployment depth below sea level in meters c = 1.500 # P-wave velocity in salt water (km/s) rhof = 1027. # Density of salt water (kg/m^3) slow = 0.06 # Horizontal slowness (or ray parameter) in s/km # Back-azimuth direction in degrees # (has no influence if model is isotropic) baz = 0. model = ut.read_model(modfile) assert list(model.rho) == [2800.0, 2800.0, 3200.0] t1 = ut.calc_ttime(model, slow, wvtype=wvtype) assert round(t1, 1) == 1.1 trxyz = ut.run_plane(model, slow, npts, dt, baz=baz, wvtype=wvtype, obs=True, dp=dp, c=c, rhof=rhof) tfs = ut.tf_from_xyz(trxyz, pvh=False) ntr = trxyz[0] # North component etr = trxyz[1] # East component ztr = trxyz[2] # Vertical component rtr = ntr.copy() # Radial component ttr = etr.copy() # Transverse component rtr.data, ttr.data = rotate_ne_rt(ntr.data, etr.data, baz) strf = Stream(traces=[tfs[0], ztr, rtr]) # Set frequency corners in Hz f1 = 0.1 f2 = 1.0 # Plot as wiggles with tempfile.TemporaryDirectory() as tempdir: wg.pw_wiggles_Audet2016(strf, t1=t1, tmax=10., f1=f1, f2=f2, ftitle=join(tempdir, 'audet2016'), scale=2.e-7, save=True)
def check_rotation_examples(N, E, angles): """ Check rotation angles by rotating the partially rotated the rest of the way to 360 since obspy doesn't do the negative and compare to original values. Should be close to zero""" ntests = 0 testsfailed = 0 for angle in angles: dir = "%03d" % (angle) n = read("%s/%s" % (dir, N[0].stats.id)) e = read("%s/%s" % (dir, N[0].stats.id)) r, t = rotate.rotate_ne_rt(n[0].data, e[0].data, 360. - angle) try: npt.assert_almost_equal(N[0].data, r) ntests += 1 npt.assert_almost_equal(E[0].data, t) ntests += 1 except: testsfailed += 1 print("Check rotation %d tests passed test %d tests failed" % (ntests, testsfailed)) return True
def create_rotation_examples(N, E, angles): for angle in angles: # We add 180 because the angle is back azimuth. The rotation does not allow # negative angles so we continue on around the other way. if angle < 180.: rangle = angle + 180. else: rangle = angle - 180. r, t = rotate.rotate_ne_rt(N[0].data, E[0].data, rangle) dir = "rotation/%03d" % (angle) try: os.mkdir(dir) except: # Directory exists do nothing pass tr_n = N[0].copy() tr_n.data = r.astype('int32') tr_e = E[0].copy() tr_e.data = t.astype('int32') tr_n.write("%s/%s" % (dir, tr_n.id), format='MSEED') tr_e.write("%s/%s" % (dir, tr_e.id), format='MSEED')
def DLcalc(stream, Rf, LPF, HPF, epi, baz, A, winlen=10., ptype=0): """ DORAN-LASKE calculation for one freq, one orbit of surface wave ADRIAN. K. DORAN and GABI LASKE, DLOPy VERSION 1.0, RELEASED APRIL 2017 Parameters ---------- stream : float Latitude of origin point (deg) lon1 : float Longitude of origin point (deg) lat2 : float Latitude of end point (deg) lon2 : float Longitude of end point (deg) map* : :class:`~numpy.ndarray` maps of Rayleigh-wave dispersion at various frequencies Returns ------- R1 : :class:`~numpy.ndarray` R1 velocity path R2 : :class:`~numpy.ndarray` R2 velocity path """ # Pre-process stream.taper(type='hann', max_percentage=0.05) stream.filter("lowpass", freq=LPF, corners=4, zerophase=True) stream.filter("highpass", freq=HPF, corners=4, zerophase=True) stream.detrend() # Window info Rvel = getf(Rf, A) # Group velocity at Rf R1window = (1.0 / (Rf / 1000.)) * winlen arv = 1. / Rvel * epi r1 = arv - R1window / 2. r2 = arv + R1window / 2. dt = stream[0].stats.starttime st = stream.slice(starttime=dt + r1, endtime=dt + r2) # Extract waveform data for each component tr1 = st.select(component='1')[0].data tr2 = st.select(component='2')[0].data trZ = st.select(component='Z')[0].data # Calculate Hilbert transform of vertical trace data trZ = np.imag(sig.hilbert(trZ)) # Ensure all data vectors are same length tr1, tr2, trZ = resiz(tr1, tr2, trZ) # Rotate through and find max normalized covariance dphi = 0.1 ang = np.arange(0., 360., dphi) cc1 = np.zeros(len(ang)) cc2 = np.zeros(len(ang)) for k, a in enumerate(ang): R, T = rotate_ne_rt(tr1, tr2, a) covmat = np.corrcoef(R, trZ) cc1[k] = covmat[0, 1] cstar = np.cov(trZ, R) / np.cov(trZ) cc2[k] = cstar[0, 1] # Get argument of maximum of cc2 ia = cc2.argmax() # Get azimuth and correct for angles above 360 phi = (baz - float(ia) * dphi) + 180. if phi < 0.: phi += 360. if phi >= 360.: phi -= 360. # # plotting: # # ptype=0, no plot # # ptype=1, Rayleigh plot # # ptype=2, Love plot # if ptype == 1: # import matplotlib.dates as dat # X = P[0].times() # T = np.zeros((len(X))) # for q in np.arange((len(T))): # T[q] = dt + r1 + X[q] # ZZ = dat.epoch2num(T) # Z = dat.num2date(ZZ) # n, e = rot2d(rdat, rdat2, ANG/4.) # plt.figure() # plt.plot(Z, vdat, label='Vertical') # plt.hold("on") # plt.plot(Z, n, label='BH1') # plt.legend(loc=4) # plt.xlabel('Time') # plt.ylabel('Counts') # plt.title('D-L Results (%i mHz)' % (Rf)) # elif ptype == 2: # import matplotlib.dates as dat # X = P[0].times() # T = np.zeros((len(X))) # for q in np.arange((len(T))): # T[q] = dt+r1+X[q] # ZZ = dat.epoch2num(T) # Z = dat.num2date(ZZ) # n, e = rot2d(rdat, rdat2, ANG/4.) # plt.figure() # plt.subplot(121) # plt.plot(Z, vdat, label='Vertical') # plt.hold("on") # plt.plot(Z, n, label='BH1') # plt.legend(loc=4) # plt.xlabel('Time') # plt.suptitle('D-L Results (%i mHz)' % (Rf)) # plt.subplot(122) # plt.plot(Z, e, label='BH2') # plt.xlabel('Time') # plt.ylabel('Counts') # plt.legend(loc=4) # elif ptype == 3: # import matplotlib.dates as dat # X = P[0].times() # T = np.zeros((len(X))) # for q in np.arange((len(T))): # T[q] = dt+r1+X[q] # n, e = rot2d(rdat, rdat2, ANG/4.) # plt.figure() # plt.plot(T, vdat, label='Vertical') # if ptype > 0: # plt.show() return phi, cc1[ia]
def get_P_rf(self, window_start=-10.0, window_end=100.0, wl = 0.1, rotation_method = 'RTZ', type = 'earth_model',plot = False, decon_type='water_level'): self.window_start = window_start self.window_end = window_end #initialize receiver function time series len_s = self.window_end - self.window_start len_i = int(len_s/self.ses3d_seismogram.dt) if(type == 'earth_model'): model = TauPyModel(model='pyrolite_5km') tt = model.get_travel_times(source_depth_in_km = self.eq_depth, distance_in_degree = self.delta_deg, phase_list=["P","P660s"]) #just in case there's more than one phase arrival, loop through tt list for i in range(0,len(tt)): if tt[i].name == 'P': p_wave_arrival = tt[i].time p_i = int(p_wave_arrival / self.ses3d_seismogram.dt) elif tt[i].name == 'P660s': self.slowness = tt[i].ray_param * (np.pi/180.0) elif(type == 'toy_model'): p_i = np.argmax(self.ses3d_seismogram.trace_z) p_wave_arrival = p_i * self.ses3d_seismogram.dt #window seismograms to [P-window_start : P+window_end] wi_start = int((p_wave_arrival+window_start)/self.ses3d_seismogram.dt) wi_end = int((p_wave_arrival+window_end)/self.ses3d_seismogram.dt) trace_x_windowed = self.ses3d_seismogram.trace_x[wi_start:wi_end] trace_y_windowed = self.ses3d_seismogram.trace_y[wi_start:wi_end] trace_z_windowed = self.ses3d_seismogram.trace_z[wi_start:wi_end] #find incidence angle from P wave amplitudes. first rotate to rtz r_here, t_here = rotate.rotate_ne_rt(trace_x_windowed, trace_y_windowed, self.back_az) z_here = trace_z_windowed r_amp = np.amax(r_here) z_amp = np.amax(z_here) incidence_angle = np.arctan(r_amp/z_amp) * (180/np.pi) #rotate if rotation_method == 'RTZ': self.r, self.t = rotate.rotate_ne_rt(trace_x_windowed, trace_y_windowed, self.back_az) self.z = trace_z_windowed elif rotation_method == 'LQT' and type == 'earth_model': self.z, self.r, self.t = rotate.rotate_zne_lqt(trace_z_windowed, trace_x_windowed, trace_y_windowed, self.back_az, incidence_angle) elif rotation_method == 'LQT' and type == 'toy_model': raise ValueError('rotation method LQT not implemented for type : toy_model') #deconvolve Z (apprx. P wave pulse) from R self.time = np.linspace(window_start, window_end, len(self.r)) if decon_type == 'water_level': self.prf = water_level(self.r,self.z,wl) elif decon_type == 'damped_lstsq': self.prf = damped_lstsq(self.r,self.z,damping=0.001) #plot the two waveforms being deconvolved if plot == True: plt.plot(self.time, self.r) plt.plot(self.time, self.z) if decon_type=='water_level': #center of the receiver function on the P arrival spike = np.exp((-1.0*(self.time)**2)/0.1) spike_omega = np.fft.fft(spike) prf_omega = np.fft.fft(self.prf) prf_shifted = spike_omega*prf_omega self.prf = np.real(np.fft.ifft(prf_shifted)) #normalize self.prf /= self.prf.max() if rotation_method=='LQT': self.prf *= -1.0
def tf_from_xyz(trxyz, pvh=False): """ Function to generate transfer functions from displacement traces. Args: trxyz (obspy.stream): Obspy ``Stream`` object in cartesian coordinate system pvh (bool, optional): Whether to rotate from Z-R-T coordinate system to P-SV-SH wave mode Returns: (obspy.stream): tfs: Stream containing Radial and Transverse transfer functions """ # Extract East, North and Vertical ntr = trxyz[0] etr = trxyz[1] ztr = trxyz[2] baz = cf.baz # Copy to radial and transverse rtr = ntr.copy() ttr = etr.copy() # Rotate to radial and transverse rtr.data, ttr.data = rotate_ne_rt(ntr.data, etr.data, baz) a = pyfftw.empty_aligned(len(rtr.data), dtype='float') # print(rtr.data, ttr.data) if pvh: vp = np.sqrt(cf.a[2,2,2,2,0])/1.e3 vs = np.sqrt(cf.a[1,2,1,2,0])/1.e3 trP, trV, trH = rotate_zrt_pvh(ztr, rtr, ttr, vp=vp, vs=vs) tfr = trV.copy(); tfr.data = np.zeros(len(tfr.data)) tft = trH.copy(); tft.data = np.zeros(len(tft.data)) ftfv = pyfftw.interfaces.numpy_fft.fft(trV.data) ftfh = pyfftw.interfaces.numpy_fft.fft(trH.data) ftfp = pyfftw.interfaces.numpy_fft.fft(trP.data) if cf.wvtype=='P': # Transfer function tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(ftfv,ftfp)))) tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(ftfh,ftfp)))) elif cf.wvtype=='Si': tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfp,ftfv)))) tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfp,ftfh)))) elif cf.wvtype=='SV': tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfp,ftfv)))) elif cf.wvtype=='SH': tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfp,ftfh)))) else: tfr = rtr.copy(); tfr.data = np.zeros(len(tfr.data)) tft = ttr.copy(); tft.data = np.zeros(len(tft.data)) ftfr = pyfftw.interfaces.numpy_fft.fft(rtr.data) ftft = pyfftw.interfaces.numpy_fft.fft(ttr.data) ftfz = pyfftw.interfaces.numpy_fft.fft(ztr.data) if cf.wvtype=='P': # Transfer function tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(ftfr,ftfz)))) tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(ftft,ftfz)))) elif cf.wvtype=='Si': tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfz,ftfr)))) tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfz,ftft)))) elif cf.wvtype=='SV': tfr.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfz,ftfr)))) elif cf.wvtype=='SH': tft.data = np.fft.fftshift(np.real(pyfftw.interfaces.numpy_fft.ifft(np.divide(-ftfz,ftft)))) # Store in stream tfs = Stream(traces=[tfr, tft]) # Return stream return tfs
def tf_from_xyz(trxyz, pvh=False, vp=None, vs=None): """ Function to generate transfer functions from displacement traces. Args: trxyz (obspy.stream): Obspy ``Stream`` object in cartesian coordinate system pvh (bool, optional): Whether to rotate from Z-R-T coordinate system to P-SV-SH wave mode vp (float, optional): Vp velocity at surface for rotation to P-SV-SH system vs (float, optional): Vs velocity at surface for rotation to P-SV-SH system Returns: (obspy.stream): tfs: Stream containing Radial and Transverse transfer functions """ # Extract East, North and Vertical ntr = trxyz[0] etr = trxyz[1] ztr = trxyz[2] baz = ntr.stats.baz slow = ntr.stats.slow wvtype = ntr.stats.wvtype # Copy to radial and transverse rtr = ntr.copy() ttr = etr.copy() # Rotate to radial and transverse rtr.data, ttr.data = rotate_ne_rt(ntr.data, etr.data, baz) if pvh: trP, trV, trH = rotate_zrt_pvh(ztr, rtr, ttr, slow, vp=vp, vs=vs) tfr = trV.copy() tfr.data = np.zeros(len(tfr.data)) tft = trH.copy() tft.data = np.zeros(len(tft.data)) ftfv = fft(trV.data) ftfh = fft(trH.data) ftfp = fft(trP.data) if wvtype == 'P': # Transfer function tfr.data = fftshift(np.real(ifft(np.divide(ftfv, ftfp)))) tft.data = fftshift(np.real(ifft(np.divide(ftfh, ftfp)))) elif wvtype == 'Si': tfr.data = fftshift(np.real(ifft(np.divide(-ftfp, ftfv)))) tft.data = fftshift(np.real(ifft(np.divide(-ftfp, ftfh)))) elif wvtype == 'SV': tfr.data = fftshift(np.real(ifft(np.divide(-ftfp, ftfv)))) elif wvtype == 'SH': tft.data = fftshift(np.real(ifft(np.divide(-ftfp, ftfh)))) else: tfr = rtr.copy() tfr.data = np.zeros(len(tfr.data)) tft = ttr.copy() tft.data = np.zeros(len(tft.data)) ftfr = fft(rtr.data) ftft = fft(ttr.data) ftfz = fft(ztr.data) if wvtype == 'P': # Transfer function tfr.data = fftshift(np.real(ifft(np.divide(ftfr, ftfz)))) tft.data = fftshift(np.real(ifft(np.divide(ftft, ftfz)))) elif wvtype == 'Si': tfr.data = fftshift(np.real(ifft(np.divide(-ftfz, ftfr)))) tft.data = fftshift(np.real(ifft(np.divide(-ftfz, ftft)))) elif wvtype == 'SV': tfr.data = fftshift(np.real(ifft(np.divide(-ftfz, ftfr)))) elif wvtype == 'SH': tft.data = fftshift(np.real(ifft(np.divide(-ftfz, ftft)))) # Store in stream tfs = Stream(traces=[tfr, tft]) # Return stream return tfs
def getobs(mseed_filename, client, event, phases, frq4, windows, stas, stalocs, picks=None, delta_T={ 'P': 1., 'SH': 1., 'R': 10., 'L': 10. }, taper=None, adjtime=None): # Connect to arclink server #st = read('../mseed/mini.seed') org = event.preferred_origin() if org is None: org = event.origins[0] st = read(mseed_filename) stobs = {'params': {'filter': frq4, 'windows': windows}} syn = {} torg = org.time trngmx = 3600. invout = None # First do any requried time adjustments if not adjtime is None: for tr in st: if not tr.stats.station in adjtime.keys(): continue print 'Adjusting time for station %s by %g secs' % \ (tr.stats.station,adjtime[tr.stats.station]) tr.stats.starttime -= adjtime[tr.stats.station] for phase in phases: if not phase in stas.keys(): continue stobs[phase] = Stream() for sta in stas[phase]: # If this is a body wave phase find the pick - skip if none found if phase == 'P' or phase == 'SH': sta_pick = None # If no picks supplied then get them from events if picks is None: for pick in event.picks: if pick.phase_hint == phase[0:1] and \ pick.waveform_id.station_code == sta: sta_pick = pick break else: # Get them from picks - e.g. returned by get_isctimes if sta in picks.keys() and phase[0:1] in picks[sta]: sta_pick = Pick() sta_pick.time = picks[sta][phase[0:1]] if sta_pick is None: print 'No %s pick found for station %s - skipping' % ( phase, sta) continue # Set location code if prescribed, otherwise use '00' (preferred) if sta in stalocs.keys(): loc = stalocs[sta] else: loc = '00' # Select the channels for this station - skip if none found chans = st.select(station=sta, location=loc) if len(chans) == 0: # if nothing for loc='00', try also with '' loc = '' chans = st.select(station=sta, location=loc) if len(chans) == 0: print 'No channels found for %s' % sta continue try: inv = client.get_stations(network=chans[0].stats.network, station=sta, location=loc, starttime=torg, endtime=torg + 100., level='response') except Exception as e: warnings.warn(str(e)) print 'FDSNWS request failed for trace id %s - skipping' % sta continue try: coordinates = inv[0].get_coordinates(chans[0].id) except: print 'No coordinates found for station %s, channel %s' % \ (sta,chans[0].id) continue dist, azm, bazm = gps2dist_azimuth(org['latitude'], org['longitude'], coordinates['latitude'], coordinates['longitude']) gcarc = locations2degrees(org['latitude'], org['longitude'], coordinates['latitude'], coordinates['longitude']) if phase == 'R' or phase == 'P': # Rayleigh or P wave try: tr = st.select(station=sta, component='Z', location=loc)[0] except IndexError: print 'No vertical for %s:%s' % (sta, loc) continue try: inv = client.get_stations(network=tr.stats.network, station=sta, channel=tr.stats.channel, location=loc, starttime=torg, endtime=torg + 100., level='response') except Exception as e: warnings.warn(str(e)) print 'FDSNWS request failed for trace id %s - skipping' % tr.id continue tr = tr.copy() tr.stats.response = inv[0].get_response(tr.id, torg) tr.stats.coordinates = inv[0].get_coordinates(tr.id) tr.remove_response(pre_filt=frq4[phase], output='DISP') tr.stats.gcarc = gcarc tr.stats.azimuth = azm #t1 = minv[0].get_responeax(tr.stats.starttime,t+dist/rvmax) #t2 = min(tr.stats.endtime ,t+dist/rvmin) t1 = max(torg, tr.stats.starttime) t2 = min(torg + trngmx, tr.stats.endtime) tr.trim(starttime=t1, endtime=t2) decim = int(0.01 + delta_T[phase] / tr.stats.delta) ch = inv.select(station=sta, channel=tr.stats.channel)[0][0][0] print tr.id,' ',tr.stats.sampling_rate,' decimated by ',decim,\ 'sensitivity=',ch.response.instrument_sensitivity.value if tr.stats.starttime - torg < 0.: tr.trim(starttime=torg) tr.decimate(factor=decim, no_filter=True) tr.data *= 1.e6 # Convert to microns elif phase == 'L' or phase == 'SH': # Love or SH wave if len(chans.select(component='E')) != 0: try: tr1a = st.select(station=sta, component='E', location=loc)[0] tr2a = st.select(station=sta, component='N', location=loc)[0] except: print 'Station %s does not have 2 horizontal componets -skipping' % sta continue elif len(chans.select(component='1')) != 0: try: tr1a = st.select(station=sta, component='1', location=loc)[0] tr2a = st.select(station=sta, component='2', location=loc)[0] except: print 'Station %s does not have 2 horizontal componets -skipping' % sta continue tr1 = tr1a.copy() tr1.data = tr1a.data.copy() tr2 = tr2a.copy() tr2.data = tr2a.data.copy() ch1 = inv.select(station=sta, channel=tr1.stats.channel)[0][0][0] ch2 = inv.select(station=sta, channel=tr2.stats.channel)[0][0][0] tr1.stats.response = ch1.response tr1.remove_response(pre_filt=frq4[phase], output='DISP') tr2.stats.response = ch2.response tr2.remove_response(pre_filt=frq4[phase], output='DISP') strt = max(tr1.stats.starttime, tr2.stats.starttime) endt = min(tr1.stats.endtime, tr2.stats.endtime) tr1.trim(starttime=strt, endtime=endt) tr2.trim(starttime=strt, endtime=endt) # Rotate components first to ZNE vert, north, east = rotate2zne(tr1.data, ch1.azimuth, 0., tr2.data, ch2.azimuth, 0., np.zeros(tr1.stats.npts), 0., 0.) radial, transverse = rotate_ne_rt(north, east, bazm) tr = Trace(header=tr1.stats, data=transverse) tr2 = Trace(header=tr2.stats, data=radial) tr.stats.channel = tr.stats.channel[:-1] + 'T' # Change one of the invout channels to end in 'T' net = inv[-1] stn = net[0] chn = stn[0] chn.code = chn.code[:-1] + 'T' # tr.stats.gcarc = gcarc tr.stats.azimuth = azm decim = int(0.01 + delta_T[phase] / tr.stats.delta) print tr.id, ' ', tr.stats.sampling_rate, ' decimated by ', decim print '%s: sensitivity=%g, azimuth=%g, dip=%g' % ( ch1.code, ch1.response.instrument_sensitivity.value, ch1.azimuth, ch1.dip) print '%s: sensitivity=%g, azimuth=%g, dip=%g' % ( ch2.code, ch2.response.instrument_sensitivity.value, ch2.azimuth, ch2.dip) if tr.stats.starttime - torg < 0.: tr.trim(starttime=torg) tr2.trim(starttime=torg) tr.decimate(factor=decim, no_filter=True) tr2.decimate(factor=decim, no_filter=True) tr.radial = 1.e6 * tr2.data tr.stats.coordinates = coordinates tr.data *= 1.e6 # Convert to microns if phase == 'R' or phase == 'L': # Window according to group velocity window gwin = windows[phase] tbeg, tend = (dist * .001 / gwin[1], dist * .001 / gwin[0]) tr.trim(torg + tbeg, torg + tend) elif phase == 'P' or phase == 'SH': # Window by times before and after pick tbef, taft = windows[phase] tr.trim(sta_pick.time - tbef, sta_pick.time + taft) idx = int(0.5 + tbef / tr.stats.delta) avg = tr.data[:idx].mean() tr.data -= avg if not taper is None: itp = int(taper * tr.stats.npts) for i in range(tr.stats.npts - itp, tr.stats.npts): tr.data[i] *= 0.5 * (1. + mt.cos( mt.pi * (i - (tr.stats.npts - itp)) / float(itp))) tr.stats.pick = sta_pick stobs[phase].append(tr) # Appen station inventory to invout if invout is None: invout = inv else: invout += inv # Pickle to file return stobs, invout
def SKS_Intensity_Chevrot(st_ev, ev_time, t_SKS, back_azimut, plot=True): # SV_Az = [] # Az = [] st_ev = st_ev.sort() # for ev_step in range(0,len(ev_time_l)): ### SORT IT AS ZNE st_stream = obspy.Stream() tmp = st_ev[2] st_stream += tmp tmp = st_ev[1] st_stream += tmp tmp = st_ev[0] st_stream += tmp gridspec.GridSpec(2, 3) arrival_time = ev_time + t_SKS ### USE CORRECT ARRIVAL TIME ### Take small time window around arrival time twin = 15 st_stream = st_stream.slice(arrival_time - twin, arrival_time + twin, nearest_sample=True) limits = np.max([abs(st_stream[2].data), abs(st_stream[2].data)]) * 2 * 10**6 #### CALC THE POLARIZATION OF PARTICLE MOTION ## only accept the upper half for Signal noise_level = st_stream[0].data**2 + st_stream[1].data**2 + st_stream[ 2].data**2 azimuth, incidence, az_error, in_error = particle_motion_odr( st_stream, noise_thres=np.mean([np.max(noise_level), np.min(noise_level)]) + np.std([np.max(noise_level), np.min(noise_level)])) # print(az_error) ### ROTATE THE SYSTEM FROM NE TO RT st_rot_RT = rotate_ne_rt(st_stream[1].data, st_stream[2].data, 180 + azimuth) radial = st_rot_RT[0] r_dot = np.diff(radial) / st_stream[1].stats.delta radial = radial[0:len(r_dot)] transverse = st_rot_RT[1][0:len(r_dot)] r_2 = np.sum(r_dot**2) ### NORMALIZE SPLITTING VECTOR SV_EQ = -np.sum(2 * r_dot * transverse) / r_2 sigma = np.sqrt(np.sum((transverse + 0.5 * r_dot * SV_EQ)**2)) # print(sigma) ### EVENT AZIMUT IS BACK-AZIMUT +180 if back_azimut + 180 > 360: Az = back_azimut - 180 else: Az = back_azimut + 180 SV_Az = SV_EQ if plot == True: ### Only Plotting Below fig = plt.figure(figsize=(16, 9)) # plt.subplot2grid((2,3), (0,0), colspan=2, rowspan=1) ax1 = fig.add_axes([0.1, 0.5, 0.5, 0.3]) ax2 = fig.add_axes([0.65, 0.5, 0.25, 0.3]) ax3 = fig.add_axes([0.1, 0.1, 0.5, 0.3]) ax4 = fig.add_axes([0.65, 0.1, 0.25, 0.3]) timevec = np.linspace(float(st_stream[0].stats.starttime), float(st_stream[0].stats.endtime), st_stream[0].stats.npts) xxticks = np.linspace(timevec[0], timevec[-1], 10) xxlabels = [] for i in range(0, len(xxticks)): tmp = UTCDateTime(xxticks[i]).strftime('%H:%M:%S') xxlabels.append(tmp) ########### SET PROPER TIME AXIS ax1.plot(timevec, st_stream[1].data * 10**6, 'g', label='North') ax1.plot(timevec, st_stream[2].data * 10**6, 'b', label='East') ax1.vlines( x=float(arrival_time), ymin=1.3 * np.min( np.min([st_stream[1].data * 10**6, st_stream[2].data * 10**6 ])), ymax=1.3 * np.max( np.max([st_stream[1].data * 10**6, st_stream[2].data * 10**6 ])), color='k', linewidth=0.5, label='SKS-Phase') ax1.set_title( '{0}, SKS-arrival at: {1}, Backazimut={2} $^\circ$, SI={3}'.format( st_stream[0].stats.station, arrival_time.strftime('%Y-%m-%d, %H:%M:%S'), round(Az, 2), round(SV_Az, 2))) ax1.set_xlabel('Time [s]') ax1.set_ylabel('displacement [$\mu$m]') ax1.set_xlim(timevec[0], timevec[-1]) ax1.set_xticks(xxticks) ax1.set_xticklabels(xxlabels) ax1.grid() ax1.legend() # plt.subplot2grid((2,3), (0,2)) ax2.plot(st_stream[2].data * 10**6, st_stream[1].data / 10**-6, color='black', linestyle='dashed') ax2.set_xlabel('East disp. [$\mu$m]') ax2.set_ylabel('North disp. [$\mu$m]') ax2.axis('equal') ax2.set_xlim(-limits, limits) ax2.set_ylim(-limits, limits) ax2.grid() ax2.set_title('Polarization: Azimuth={0}$^\circ$'.format( round(azimuth, 2))) # limits = 1 # limits = np.max([np.max(radial),np.max(transverse)]) # # plt.subplot2grid((2,3), (1,0), colspan=2, rowspan=1) ax3.plot(timevec[0:-1], radial * 10**6, 'r', label='Radial') ax3.plot(timevec[0:-1], transverse * 10**6, 'b', label='Transverse') ax3.plot(timevec[0:-1], -0.5 * r_dot * (np.max(transverse) / np.max(r_dot)) * 10**6, color='g', label='radial-derivate', alpha=0.5, linewidth=0.5) ax3.vlines( x=float(arrival_time), ymin=1.3 * np.min( np.min([st_stream[1].data * 10**6, st_stream[2].data * 10**6 ])), ymax=1.3 * np.max( np.max([st_stream[1].data * 10**6, st_stream[2].data * 10**6 ])), color='k', linewidth=0.5, label='SKS-Phase') ax3.set_xlabel('Time [s]') ax3.set_ylabel('displacement [$\mu$m]') ax3.set_xlim(timevec[0], timevec[-1]) ax3.set_xticks(xxticks) ax3.set_xticklabels(xxlabels) ax3.grid() ax3.set_title('rotated System') ax3.legend() # plt.subplot2grid((2,3), (1,2)) ax4.plot(radial * 10**6, transverse * 10**6, color='black', linestyle='dashed') ax4.set_xlabel('Radial disp. [$\mu$m]') ax4.set_ylabel('Transverse disp. [$\mu$m]') ax4.axis('equal') # ax4.set_xlim(-limits, limits) # ax4.set_ylim(-limits, limits) ax4.grid() try: path_Methods = '/media/hein/home2/SplitWave_Results/Splitting_Intensity/{0}/'.format( st_stream[0].stats.station) os.mkdir(path_Methods) except: pass plt.savefig( '/media/hein/home2/SplitWave_Results/Splitting_Intensity/{0}/{0}_{1}' .format(st_stream[0].stats.station, arrival_time.strftime('%Y-%m-%d, %H:%M:%S'))) plt.close() # fig.close() # plt.show() return Az, SV_Az
def extract_s(taupy_model, picker, event, station_longitude, station_latitude, stn, ste, ba, win_start=-50, win_end=50, resample_hz=20, bp_freqmins=[0.05, 2], bp_freqmaxs=[0.5, 5], margin=20, max_amplitude=1e8): po = event.preferred_origin if (not po): return None atimes = [] try: atimes = taupy_model.get_travel_times_geo(po.depthkm, po.lat, po.lon, station_latitude, station_longitude, phase_list=('S', )) except: return None # end try if (len(atimes) == 0): return None tat = atimes[0].time # theoretical arrival time tr = None try: stn = stn.slice(po.utctime + tat + win_start, po.utctime + tat + win_end) stn.resample(resample_hz) if (ste): ste = ste.slice(po.utctime + tat + win_start, po.utctime + tat + win_end) ste.resample(resample_hz) # end if if (ste): if (type(stn[0].data) == np.ndarray and type(ste[0].data) == np.ndarray): rc, tc = rotate_ne_rt(stn[0].data, ste[0].data, ba) tr = Trace(data=tc, header=stn[0].stats) #tr = Trace(data=np.sqrt(np.power(rc,2) + np.power(tc,2)), header=stn[0].stats) # end if else: if (type(stn[0].data) == np.ndarray): tr = stn[0] # end if # end if except Exception as e: return None # end try if (tr): if (np.max(tr.data) > max_amplitude): return None pickslist = [] snrlist = [] residuallist = [] tr.detrend('linear') for i in range(len(bp_freqmins)): trc = tr.copy() trc.filter('bandpass', freqmin=bp_freqmins[i], freqmax=bp_freqmaxs[i], corners=4, zerophase=True) try: scnl, picks, polarity, snr, uncert = picker.picks(trc) for ipick, pick in enumerate(picks): actualArrival = pick - po.utctime residual = actualArrival - tat if (np.fabs(residual) < margin): pickslist.append(pick) snrlist.append(snr[ipick]) residuallist.append(residual) #summary = fbpicker.FBSummary(picker, trc) #summary = aicdpicker.AICDSummary(picker, trc) #outputPath = '/home/rakib/work/pst/picking/sarr' #outputPath = '/g/data1a/ha3/rakib/seismic/pst/tests/plots/new' #ofn = '%s/%s.%s_%f_%d.s.png' % (outputPath, scnl, str(po.utctime), snr[0], i) #summary.plot_picks(show=False, savefn=ofn) # end if # end for except: continue # end try # end for if (len(pickslist)): optimal_pick_idx = np.argmax(np.array(snrlist)) return pickslist[optimal_pick_idx], residuallist[optimal_pick_idx], \ snrlist[optimal_pick_idx], optimal_pick_idx # end if # end if return None
def extract_s(taupy_model, pickerlist, event, station_longitude, station_latitude, stn, ste, ba, win_start=-50, win_end=50, resample_hz=20, bp_freqmins=[0.01, 0.01, 0.5], bp_freqmaxs=[1, 2., 5.], margin=None, max_amplitude=1e8, plot_output_folder=None): po = event.preferred_origin if (not po): return None atimes = [] try: atimes = taupy_model.get_travel_times_geo(po.depthkm, po.lat, po.lon, station_latitude, station_longitude, phase_list=('S', )) except: return None # end try if (len(atimes) == 0): return None tat = atimes[0].time # theoretical arrival time buffer_start = -10 buffer_end = 10 snrtr = None try: stn = stn.slice(po.utctime + tat + win_start + buffer_start, po.utctime + tat + win_end + buffer_end) stn = stn.copy() stn.resample(resample_hz) stn.detrend('linear') if (ste): ste = ste.slice(po.utctime + tat + win_start + buffer_start, po.utctime + tat + win_end + buffer_end) ste = ste.copy() ste.resample(resample_hz) ste.detrend('linear') # end if if (ste): if (type(stn[0].data) == np.ndarray and type(ste[0].data) == np.ndarray): rc, tc = rotate_ne_rt(stn[0].data, ste[0].data, ba) snrtr = Trace(data=tc, header=stn[0].stats) snrtr.detrend('linear') # end if else: if (type(stn[0].data) == np.ndarray): snrtr = stn[0] # end if # end if except Exception as e: return None # end try if (type(snrtr.data) == np.ndarray): if (np.max(snrtr.data) > max_amplitude): return None pickslist = [] snrlist = [] residuallist = [] bandindex = -1 pickerindex = -1 taper_percentage = float(buffer_end) / float(win_end) foundpicks = False for i in range(len(bp_freqmins)): trc = snrtr.copy() trc.taper(max_percentage=taper_percentage, type='hann') trc.filter('bandpass', freqmin=bp_freqmins[i], freqmax=bp_freqmaxs[i], corners=4, zerophase=True) trc = trc.slice(po.utctime + tat + win_start, po.utctime + tat + win_end) for ipicker, picker in enumerate(pickerlist): try: scnl, picks, polarity, snr, uncert = picker.picks(trc) for ipick, pick in enumerate(picks): actualArrival = pick - po.utctime residual = actualArrival - tat if ((margin and np.fabs(residual) < margin) or (margin == None)): pickslist.append(pick) plotinfo = None if (plot_output_folder): plotinfo = { 'eventid': event.public_id, 'origintime': po.utctime, 'mag': event.preferred_magnitude.magnitude_value, 'net': trc.stats.network, 'sta': trc.stats.station, 'phase': 's', 'ppsnr': snr[ipick], 'pickid': ipick, 'outputfolder': plot_output_folder } # end if wab = snrtr.slice(pick - 3, pick + 3) wab_filtered = trc.slice(pick - 3, pick + 3) scales = np.logspace(0.5, 4, 30) cwtsnr, dom_freq, slope_ratio = compute_quality_measures( wab, wab_filtered, scales, plotinfo) snrlist.append( [snr[ipick], cwtsnr, dom_freq, slope_ratio]) residuallist.append(residual) bandindex = i pickerindex = ipicker foundpicks = True # end if # end for except: continue # end try if (foundpicks): break # end for if (foundpicks): break # end for if (len(pickslist)): return pickslist, residuallist, \ np.array(snrlist), bandindex, pickerindex # end if # end if return None
def get_P_rf(self, window_start=-10.0, window_end=100.0, wl=0.1, rotation_method='RTZ', type='earth_model', plot=False, decon_type='water_level'): self.window_start = window_start self.window_end = window_end #initialize receiver function time series len_s = self.window_end - self.window_start len_i = int(len_s / self.ses3d_seismogram.dt) if (type == 'earth_model'): model = TauPyModel(model='pyrolite_5km') tt = model.get_travel_times(source_depth_in_km=self.eq_depth, distance_in_degree=self.delta_deg, phase_list=["P", "P660s"]) #just in case there's more than one phase arrival, loop through tt list for i in range(0, len(tt)): if tt[i].name == 'P': p_wave_arrival = tt[i].time p_i = int(p_wave_arrival / self.ses3d_seismogram.dt) elif tt[i].name == 'P660s': self.slowness = tt[i].ray_param * (np.pi / 180.0) elif (type == 'toy_model'): p_i = np.argmax(self.ses3d_seismogram.trace_z) p_wave_arrival = p_i * self.ses3d_seismogram.dt #window seismograms to [P-window_start : P+window_end] wi_start = int( (p_wave_arrival + window_start) / self.ses3d_seismogram.dt) wi_end = int((p_wave_arrival + window_end) / self.ses3d_seismogram.dt) trace_x_windowed = self.ses3d_seismogram.trace_x[wi_start:wi_end] trace_y_windowed = self.ses3d_seismogram.trace_y[wi_start:wi_end] trace_z_windowed = self.ses3d_seismogram.trace_z[wi_start:wi_end] #find incidence angle from P wave amplitudes. first rotate to rtz r_here, t_here = rotate.rotate_ne_rt(trace_x_windowed, trace_y_windowed, self.back_az) z_here = trace_z_windowed r_amp = np.amax(r_here) z_amp = np.amax(z_here) incidence_angle = np.arctan(r_amp / z_amp) * (180 / np.pi) #rotate if rotation_method == 'RTZ': self.r, self.t = rotate.rotate_ne_rt(trace_x_windowed, trace_y_windowed, self.back_az) self.z = trace_z_windowed elif rotation_method == 'LQT' and type == 'earth_model': self.z, self.r, self.t = rotate.rotate_zne_lqt( trace_z_windowed, trace_x_windowed, trace_y_windowed, self.back_az, incidence_angle) elif rotation_method == 'LQT' and type == 'toy_model': raise ValueError( 'rotation method LQT not implemented for type : toy_model') #deconvolve Z (apprx. P wave pulse) from R self.time = np.linspace(window_start, window_end, len(self.r)) if decon_type == 'water_level': self.prf = water_level(self.r, self.z, wl) elif decon_type == 'damped_lstsq': self.prf = damped_lstsq(self.r, self.z, damping=0.001) #plot the two waveforms being deconvolved if plot == True: plt.plot(self.time, self.r) plt.plot(self.time, self.z) if decon_type == 'water_level': #center of the receiver function on the P arrival spike = np.exp((-1.0 * (self.time)**2) / 0.1) spike_omega = np.fft.fft(spike) prf_omega = np.fft.fft(self.prf) prf_shifted = spike_omega * prf_omega self.prf = np.real(np.fft.ifft(prf_shifted)) #normalize self.prf /= self.prf.max() if rotation_method == 'LQT': self.prf *= -1.0
elif st[itr].stats.channel == H2comp: h2 = st[itr].data elif st[itr].stats.channel == Zcomp: z = st[itr].data ba = st[0].stats.sac.baz # Rotate Z-H1-H2 to Z-N-E traces_zne = rotate2zne(data_1=z , azimuth_1=0, dip_1=-90, data_2=h1, azimuth_2=H1azi, dip_2=0, data_3=h2, azimuth_3=H1azi+90, dip_3=0) z2 = traces_zne[0] n = traces_zne[1] e = traces_zne[2] # Rotate N-E to R-T traces_rt = rotate_ne_rt(n=n, e=e, ba=ba) r = traces_rt[0] t = traces_rt[1] # Define new data streams st_bhn = st[0].copy() st_bhn.stats.channel = Ncomp st_bhn.data = n st_bhe = st[0].copy() st_bhe.stats.channel = Ecomp st_bhe.data = e st_bht = st[0].copy() st_bht.stats.channel = Tcomp st_bht.data = t st_bhr = st[0].copy() st_bhr.stats.channel = Rcomp
corrcoefs = [] for ic in xrange(0, len(RLAS[0]) // (int(sampling_rate * sec))): coeffs = xcorr(RLAS[0].data[sampling_rate * sec * ic : sampling_rate * sec * (ic + 1)], AC[0].data[sampling_rate * sec * ic : sampling_rate * sec * (ic + 1)], 0) corrcoefs.append(coeffs[1]) # estimate the Backazimuth for each time window step = 10 backas = np.linspace(0, 360 - step, 360 / step) corrbaz = [] ind=None for i6 in xrange(0, len(backas)): for i7 in xrange(0, len(corrcoefs)): corrbazz = xcorr(RLAS[0][sampling_rate * sec * i7 : sampling_rate * sec * (i7 + 1)], rotate_ne_rt(AC_original.select(component='N')[0].data, AC_original.select(component='E')[0].data, backas[i6]) [1][sampling_rate * sec * i7 : sampling_rate * sec * (i7 + 1)],0) corrbaz.append(corrbazz[1]) corrbaz = np.asarray(corrbaz) corrbaz = corrbaz.reshape(len(backas), len(corrcoefs)) maxcorr = [] for l1 in xrange(0, len(corrcoefs)): maxcor_r = backas[corrbaz[:, l1].argmax()] maxcorr.append(maxcor_r) maxcorr = np.asarray(maxcorr) X, Y = np.meshgrid(np.arange(0, sec * len(corrcoefs), sec), backas)
def calc(self, dphi, dts, tt, bp=None, showplot=False): """ Method to estimate azimuth of component `?H1` (or `?HN`). This method minimizes the energy (RMS) of the transverse component of P-wave data within some bandwidth. Parameters ---------- dphi : float Azimuth increment for search (deg) dts : float Length of time window on either side of predicted P-wave arrival time (sec) tt : list List of two floats containing the time picks relative to P-wave time, within which to perform the estimation of station orientation (sec) bp : list List of two floats containing the low- and high-frequency corners of a bandpass filter (Hz) showplot : bool Whether or not to plot waveforms. Attributes ---------- meta.phi : float Azimuth of H1 (or HN) component (deg) meta.cc : float Cross-correlation coefficient between vertical and radial component meta.snr : float Signal-to-noise ratio of P-wave measured on the vertical seismogram meta.TR : float Measure of the transverse to radial ratio. In reality this is 1 - T/R meta.RZ : float Measure of the radial to vertical ratio. In reality this is 1 - R/Z """ # Work on a copy of the waveform data stream = self.data.copy() # Filter if specified if bp: stream.filter('bandpass', freqmin=bp[0], freqmax=bp[1], zerophase=True) # Get data and noise based on symmetric waveform wrt arrival start = stream[0].stats.starttime stnoise = stream.copy().trim(start, start + dts + tt[0]) stdata = stream.copy().trim(start + dts + tt[0], start + dts + tt[1]) # Define signal and noise tr1 = stdata.select(component='1')[0].copy() tr2 = stdata.select(component='2')[0].copy() trZ = stdata.select(component='Z')[0].copy() ntrZ = stnoise.select(component='Z')[0].copy() # Calculate and store SNR as attribute self.meta.snr = 10. * np.log10( utils.rms(trZ) * utils.rms(trZ) / utils.rms(ntrZ) / utils.rms(ntrZ)) # Search through azimuths from 0 to 180 deg and find best-fit azimuth ang = np.arange(0., 180., dphi) cc1 = np.zeros(len(ang)) cc2 = np.zeros(len(ang)) cc3 = np.zeros(len(ang)) cc4 = np.zeros(len(ang)) for k, a in enumerate(ang): R, T = rotate_ne_rt(tr1.data, tr2.data, a) covmat = np.corrcoef(R, trZ.data) cc1[k] = covmat[0, 1] cc2[k] = 1. - utils.rms(T) / utils.rms(R) cc3[k] = utils.rms(T) cc4[k] = 1. - utils.rms(R) / utils.rms(trZ.data) # Get argument of minimum of cc3 and store useful measures ia = cc3.argmin() self.meta.cc = cc1[ia] self.meta.TR = cc2[ia] self.meta.RZ = cc4[ia] # correct for angles above 360 phi = (self.meta.baz - float(ia) * dphi) # Use azimuth where CC is negative if self.meta.cc < 0.: phi += 180. if phi < 0.: phi += 360. if phi >= 360.: phi -= 360. # Store the best-fit azimuth self.meta.phi = phi # If a plot is requested, rotate Z12 to ZNE and then ZRT if showplot: # Now rotate components to proper N, E and then R, T sttmp = stream.copy() # Apply filter if defined previously if bp: sttmp.filter('bandpass', freqmin=bp[0], freqmax=bp[1], zerophase=True) # Copy traces trN = sttmp.select(component='1')[0].copy() trE = sttmp.select(component='2')[0].copy() # Rotating from 1,2 to N,E is the negative of # rotation from RT to NE, with baz corresponding # to azim of component 1, or phi previously determined azim = self.meta.phi N, E = rotate_rt_ne(trN.data, trE.data, azim) trN.data = -1. * N trE.data = -1. * E # Update stats of streams trN.stats.channel = trN.stats.channel[:-1] + 'N' trE.stats.channel = trE.stats.channel[:-1] + 'E' # Store corrected traces in new stream and rotate to # R, T using back-azimuth stcorr = Stream(traces=[trN, trE]) stcorr.rotate('NE->RT', back_azimuth=self.meta.baz) # Merge original and corrected streams st = stream + stcorr # Plot plot = plotting.plot_bng_waveforms(self, st, dts, tt) plot.show() return
sec = 60 # window length for correlation num_windows = len(RLAS[0]) // (int(sampling_rate * sec)) # estimate the Backazimuth for each time window step = 10 backas = np.linspace(0, 360 - step, 360 / step) corrbaz = [] ind = None for i_deg in range(0, len(backas)): for i_win in range(0, num_windows): corrbazz = xcorr( RLAS[0][sampling_rate * sec * i_win:sampling_rate * sec * (i_win + 1)], rotate_ne_rt( AC.select(component='N')[0].data, AC.select(component='E')[0].data, backas[i_deg])[1][sampling_rate * sec * i_win:sampling_rate * sec * (i_win + 1)], 0) corrbaz.append(corrbazz[1]) corrbaz = np.asarray(corrbaz) corrbaz = corrbaz.reshape(len(backas), num_windows) maxcorr = [] for l1 in range(0, num_windows): maxcor_r = backas[corrbaz[:, l1].argmax()] maxcorr.append(maxcor_r) maxcorr = np.asarray(maxcorr) X, Y = np.meshgrid(np.arange(0, sec * num_windows, sec), backas) # - # <br>