def search_inc(self, bazi): inc_range = np.arange(0.1, 90, 0.1) s_range = self.trim(20, 20, isreturn=True) power = np.zeros(inc_range.shape[0]) for i in range(len(inc_range)): l_comp, _, _ = rotate_zne_lqt(s_range[2].data, s_range[1].data, s_range[0].data, bazi, inc_range[i]) power[i] = np.mean(l_comp**2) real_inc_idx = np.argmin(power) real_inc = inc_range[real_inc_idx] self.inc_correction = real_inc - self.inc self.inc = real_inc
def test_rotate_zne_lqt_vs_pitsa(self): """ Test LQT component rotation against PITSA. Test back-rotation. """ # load test files with gzip.open(os.path.join(self.path, 'rjob_20051006.gz')) as f: data_z = np.loadtxt(f) 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 backazimuth/incidence combinations for ba, inci in ((60, 130), (210, 60)): # rotate traces data_l, data_q, data_t = \ rotate_zne_lqt(data_z, data_n, data_e, ba, inci) # rotate traces back to ZNE data_back_z, data_back_n, data_back_e = \ rotate_lqt_zne(data_l, data_q, data_t, ba, inci) # load pitsa files with gzip.open(os.path.join(self.path, 'rjob_20051006_q_%sba_%sinc.gz' % (ba, inci))) as f: data_pitsa_q = np.loadtxt(f) with gzip.open(os.path.join(self.path, 'rjob_20051006_t_%sba_%sinc.gz' % (ba, inci))) as f: data_pitsa_t = np.loadtxt(f) with gzip.open(os.path.join(self.path, 'rjob_20051006_l_%sba_%sinc.gz' % (ba, inci))) as f: data_pitsa_l = np.loadtxt(f) # Assert the output. Has to be to rather low accuracy due to # rounding error prone rotation and single precision value. self.assertTrue( np.allclose(data_l, data_pitsa_l, rtol=1E-3, atol=1E-5)) self.assertTrue( np.allclose(data_q, data_pitsa_q, rtol=1E-3, atol=1E-5)) self.assertTrue( np.allclose(data_t, data_pitsa_t, rtol=1E-3, atol=1E-5)) self.assertTrue( np.allclose(data_z, data_back_z, rtol=1E-3, atol=1E-5)) self.assertTrue( np.allclose(data_n, data_back_n, rtol=1E-3, atol=1E-5)) self.assertTrue( np.allclose(data_e, data_back_e, rtol=1E-3, atol=1E-5))
def search_inc(self, bazi): inc_range = np.arange(0.1, 90, 0.1) # bazi_range = np.repeat(bazi, len(inc_range)) # M_all = seispy.geo.rot3D(bazi=bazi_range, inc=inc_range) # ZEN = np.array([self.rf[2].data, self.rf[0].data, self.rf[1].data]) s_range = self.trim(10, 10, phase='S', isreturn=True) # LQT_all = np.zeros([ZEN.shape[0], ZEN.shape[1], M_all.shape[2]]) power = np.zeros(inc_range.shape[0]) for i in range(len(inc_range)): # LQT_all[:, :, i] = M_all[:, :, i].dot(ZEN) l_comp, _, _ = rotate_zne_lqt(s_range[2].data, s_range[1].data, s_range[0].data, bazi, inc_range[i]) power[i] = np.mean(l_comp ** 2) # real_inc_idx = seispy.geo.extrema(power, opt='min') real_inc_idx = np.argmin(power) # print(real_inc_idx) real_inc = inc_range[real_inc_idx] return real_inc
def test_rotate2zne_against_lqt(self): np.random.seed(789) z = np.random.random(10) n = np.random.random(10) e = np.random.random(10) bas = [0.0, 14.325, 38.234, 78.1, 90.0, 136.3435, 265.4, 180.0, 351.35, 360.0] incs = [0.0, 10.325, 32.23, 88.1, 90.0, 132.3435, 245.4, 180.0, 341.35, 360.0] for ba, inc in itertools.product(bas, incs): l, q, t = rotate_zne_lqt(z=z, n=n, e=e, ba=ba, inc=inc) dip_l = (inc % 180.0) - 90.0 if 180 <= inc < 360: dip_l *= -1.0 dip_q = ((inc + 90) % 180) - 90 if 0 < inc < 90 or 270 <= inc < 360: dip_q *= -1.0 az_l = ba + 180.0 az_q = ba # Azimuths flip depending on the incidence angle. if inc > 180: az_l += 180 if 90 < inc <= 270: az_q += 180 z_new, n_new, e_new = rotate2zne(l, az_l, dip_l, q, az_q, dip_q, 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 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 test_rotate2zne_against_lqt_different_combinations(self): np.random.seed(101112) z = np.random.random(10) n = np.random.random(10) e = np.random.random(10) # Exclude coordinate axis. bas = [14.325, 38.234, 78.1, 136.3435, 265.4, 351.35] incs = [10.325, 32.23, 88.1, 132.3435, 245.4, 341.35] success_count = 0 failure_count = 0 for ba, inc in itertools.product(bas, incs): l, q, t = rotate_zne_lqt(z=z, n=n, e=e, ba=ba, inc=inc) dip_l = (inc % 180.0) - 90.0 if 180 <= inc < 360: dip_l *= -1.0 dip_q = ((inc + 90) % 180) - 90 if 0 < inc < 90 or 270 <= inc < 360: dip_q *= -1.0 az_l = ba + 180.0 az_q = ba # Azimuths flip depending on the incidence angle. if inc > 180: az_l += 180 if 90 < inc <= 270: az_q += 180 _z = [z, 0, -90, "Z"] _n = [n, 0, 0, "N"] _e = [e, 90, 0, "E"] _l = [l, az_l, dip_l, "L"] _q = [q, az_q, dip_q, "Q"] _t = [t, ba + 270, 0, "T"] # Any three of them (except three horizontal ones) should be # able to reconstruct ZNE. for a, b, c in itertools.permutations([_l, _q, _t, _z, _n, _e], 3): # Three horizontal components are linearly dependent, as are # Z, Q, and L. if a[2] == b[2] == c[2] == 0 or \ set([_i[3] for _i in (a, b, c)]) == \ set(["Z", "Q", "L"]): with self.assertRaises(ValueError) as err: rotate2zne(a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2]) self.assertTrue(err.exception.args[0].startswith( "The given directions are not linearly independent, " "at least within numerical precision. Determinant of " "the base change matrix:")) failure_count += 1 continue z_new, n_new, e_new = rotate2zne(a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2]) np.testing.assert_allclose(z_new, z) np.testing.assert_allclose(n_new, n) np.testing.assert_allclose(e_new, e) success_count += 1 # Make sure it actually tested all combinations. self.assertEqual(success_count, 3888) # Also the linearly dependent variants. self.assertEqual(failure_count, 432)
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