def test_rotate2zne_round_trip(self): """ The rotate2zne() function has an inverse argument. Thus round tripping should work. """ np.random.seed(45645623) z = np.random.random(10) n = np.random.random(10) e = np.random.random(10) for _ in range(100): # The risk of producing linear dependent directions is very # small (the seed value should also prevent it across machines). dip_1, dip_2, dip_3 = np.random.random(3) * 180.0 - 90.0 azi_1, azi_2, azi_3 = np.random.random(3) * 360.0 a, b, c = rotate2zne(z, azi_1, dip_1, n, azi_2, dip_2, e, azi_3, dip_3) z_new, n_new, e_new = rotate2zne(a, azi_1, dip_1, b, azi_2, dip_2, c, azi_3, dip_3, inverse=True) np.testing.assert_allclose(z, z_new, rtol=1E-7, atol=1e-7) np.testing.assert_allclose(n, n_new, rtol=1E-7, atol=1e-7) np.testing.assert_allclose(e, e_new, rtol=1E-7, atol=1e-7)
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 rotme(st, ang): azis = ang[0:3] dips = ang[3:6] data = rotate2zne(st[0].data, azis[0], dips[0], st[1].data, azis[1], dips[1], st[2].data, azis[2], dips[2]) st[0].data, st[1].data, st[2].data = data[0], data[1], data[2] return st
def rotate2ZNE(self): """ Rotates non ZNE stations to ZNE """ orientation_list = [] for i in range(len(self.condensed_stream)): orientation_list.append(self.condensed_stream[i].stats.channel[2]) if "E" not in orientation_list and "N" not in orientation_list: stat_orientation = [] stat_waveform = [] stat_lens = [] for i in range(len(self.condensed_stream)): stat_orientation.append( self.stn.response.get_orientation( self.condensed_stream[i].get_id())) stat_waveform.append(np.copy(self.condensed_stream[i].data)) stat_lens.append(len(stat_waveform[i])) # wavelengths must all be the same length min_len = np.min(stat_lens) waveform_array = rotate2zne(stat_waveform[0][0:min_len], stat_orientation[0]['azimuth'], stat_orientation[0]['dip'],\ stat_waveform[1][0:min_len], stat_orientation[1]['azimuth'], stat_orientation[1]['dip'],\ stat_waveform[2][0:min_len], stat_orientation[2]['azimuth'], stat_orientation[2]['dip']) for i in range(len(self.condensed_stream)): self.condensed_stream[i].data = waveform_array[i]
def test_galperin_configuration(self): """ Equal arrays on a Galperin configuration should result in only the vertical component remaining. """ dip = - (90.0 - np.rad2deg(np.arctan(np.sqrt(2.0)))) u = np.array([1.0, 0.0, 1.0]) v = np.array([1.0, 1.0, -1.0]) w = np.array([1.0, -1.0, -1.0]) z, n, e = rotate2zne( u, -90, dip, v, 30, dip, w, 150, dip) fac = 1.0 / np.sqrt(6.0) z_ref = np.array([fac * 3.0 * np.sqrt(2.0), 0.0, -fac * np.sqrt(2.0)]) n_ref = np.array([0.0, fac * 2.0 * np.sqrt(3.0), 0.0]) e_ref = np.array([0.0, 0.0, -4.0 * fac]) self.assertTrue(np.allclose(z, z_ref, rtol=1E-7, atol=1E-7)) self.assertTrue(np.allclose(n, n_ref, rtol=1E-7, atol=1E-7)) self.assertTrue(np.allclose(e, e_ref, rtol=1E-7, atol=1E-7))
def _rotate_specific_channels_to_zne( self, network, station, location, channels): """ Rotate three explicitly specified channels to ZNE. :type network: str :param network: Network code of channels that should be rotated. :type station: str :param station: Station code of channels that should be rotated. :type location: str :param location: Location code of channels that should be rotated. :type channels: list :param channels: The three channel codes of channels that should be rotated. """ from obspy.signal.rotate import rotate2ZNE as rotate2zne # build temporary stream that has only those traces that are supposed # to be used in rotation st = self.select(network=network, station=station, location=location) st = (st.select(channel=channels[0]) + st.select(channel=channels[1]) + st.select(channel=channels[2])) # remove the original unrotated traces from the stream for tr in st.traces: self.remove(tr) # cut data so that we end up with a set of matching pieces for the tree # components (i.e. cut away any parts where one of the three components # has no data) st = _trim_common_channels(st) # sort by start time, so each three consecutive traces can then be used # in one rotation run st.sort(keys=["starttime"]) # woooops, that's unexpected. must be a bug in the trimming helper # routine if len(st) % 3 != 0: msg = ("Unexpected behavior in rotation. Please file a bug " "report on github.") raise NotImplementedError(msg) num_pieces = len(st) / 3 for i in range(num_pieces): # three consecutive traces are always the ones that combine for one # rotation run traces = [st.pop() for i in range(3)] # paranoid.. do a quick check of the channels again. if set([tr.stats.channel for tr in traces]) != set(channels): msg = ("Unexpected behavior in rotation. Please file a bug " "report on github.") raise NotImplementedError(msg) zne = rotate2zne( traces[0], traces[0].stats.orientation["azimuth"], traces[0].stats.orientation["dip"], traces[1], traces[1].stats.orientation["azimuth"], traces[1].stats.orientation["dip"], traces[2], traces[2].stats.orientation["azimuth"], traces[2].stats.orientation["dip"]) for tr, new_data, component in zip(traces, zne, "ZNE"): tr.data = new_data tr.stats.channel = tr.stats.channel[:-1] + component self.traces += traces return self
def rotateZNE(st): try: zne = rotate2zne(st[0], st[0].stats.sac.cmpaz, st[0].stats.sac.cmpinc, st[1], st[1].stats.sac.cmpaz, st[1].stats.sac.cmpinc, st[2], st[2].stats.sac.cmpaz, st[2].stats.sac.cmpinc) except Exception as e: raise ValueError('No specified cmpaz or cmpinc. {}'.format(e)) for tr, new_data, component in zip(st, zne, "ZNE"): tr.data = new_data tr.stats.channel = tr.stats.channel[:-1] + component
def test_rotate2zne_round_trip(self): """ The rotate2zne() function has an inverse argument. Thus round tripping should work. """ z = np.ones(10, dtype=np.float64) n = 2.0 * np.ones(10, dtype=np.float64) e = 3.0 * np.ones(10, dtype=np.float64) # Random values. dip_1, dip_2, dip_3 = 0.0, 30.0, 60.0 azi_1, azi_2, azi_3 = 0.0, 170.0, 35.0 a, b, c = rotate2zne(z, azi_1, dip_1, n, azi_2, dip_2, e, azi_3, dip_3) z_new, n_new, e_new = rotate2zne(a, azi_1, dip_1, b, azi_2, dip_2, c, azi_3, dip_3, inverse=True) self.assertTrue(np.allclose(z, z_new, rtol=1E-7, atol=1e-7)) self.assertTrue(np.allclose(n, n_new, rtol=1E-7, atol=1e-7)) self.assertTrue(np.allclose(e, e_new, rtol=1E-7, atol=1e-7))
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_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 data_process(event2find): print('Running code for: Event ' + event2find) for i in range(0, len(event)): event1 = str(event[i]) if event1 == event2find: a = i time_1 = str(eventtime[a]) t1l = len(time_1) - 3 time_2 = time_1 class_1 = str(eventclass[a]) c1l = len(class_1) - 3 class_2 = class_1 quality_1 = str(quality[a]) q1l = len(quality_1) - 3 quality_2 = quality_1 print('Event: ' + event2find) print('Datetime of the event: ' + time_2) print('Class: ' + class_2) print('Quality: ' + quality_2) from obspy import UTCDateTime time = UTCDateTime(time_2) starttime = time - 60 * 30 print(starttime) endtime = time + 60 * 90 print(endtime) net = 'XB' sta = 'ELYSE' loc = '02' chan = 'BH*' from obspy.clients.fdsn import Client client = Client('IRIS') st = client.get_waveforms(net, sta, loc, chan, starttime, endtime, attach_response=True) print(st) # Sometimes more than one traces are available for one component, therefore a merge is necessary. for tr in st.select(component='U'): st.merge(tr) print('----------------------') print('Streams after merging') print('----------------------') print(st) timeE1 = st[0].stats.starttime timeN1 = st[1].stats.starttime timeZ1 = st[2].stats.starttime stime = max(timeE1, timeN1, timeZ1) timeEe = st[0].stats.endtime timeNe = st[1].stats.endtime timeZe = st[2].stats.endtime etime = min(timeEe, timeNe, timeZe) st[0].trim(stime, etime) st[1].trim(stime, etime) st[2].trim(stime, etime) print('----------------------') print('Streams after trimming') print('----------------------') print(st) import obspy from obspy import read from obspy import read_inventory inv = obspy.read_inventory('ELYSE.dataless') for q in range(1, 4): if q == 1: comp = ('DISP') elif q == 2: comp = ('VEL') elif q == 3: comp = ('ACC') st_rem1 = st.copy() pre_filt = [0.005, 0.01, 8, 10] #for 20 Hz data st_rem1.remove_response(output=comp, taper_fraction=0.05, pre_filt=pre_filt, inventory=inv) sta = inv[0][0] azs = [] dips = [] trs = [] channels = ['BHU', 'BHV', 'BHW'] for chn in channels: chndata = sta.select(channel=chn)[0] print('CHNDATA--------------------------------') print(chndata) azs.append(chndata.azimuth) dips.append(chndata.dip) from obspy.signal.rotate import rotate2zne (z, n, e) = rotate2zne(st_rem1[0], azs[0], dips[0], st_rem1[1], azs[1], dips[1], st_rem1[2], azs[2], dips[2]) from scipy import signal lenz = len(z) alp = 5e-2 window = signal.tukey(len(z), alpha=alp) z = z * window n = n * window e = e * window st_new1 = st_rem1.copy() st_new1[0].data = z st_new1[0].stats.channel = 'BHZ' st_new1[1].data = n st_new1[1].stats.channel = 'BHN' st_new1[2].data = e st_new1[2].stats.channel = 'BHE' print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[0].stats) print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[1].stats) print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[2].stats) import os path = ('DATA/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('DATA/' + class_2 + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('DATA/' + class_2 + '/' + quality_2 + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('DATA/' + class_2 + '/' + quality_2 + '/' + event2find + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) filename1 = (path + '/' + event2find + '_' + comp + '.mseed') st_new1.write(filename1, format='MSEED') targetfile = (path + '/' + event2find + '.mseed') from shutil import copyfile #copyfile('fdsnws_msds.mseed', targetfile) st.write(targetfile, format='MSEED')
def rotate(self, vp=None, vs=None, align=None): """ Rotates 3-component seismograms from vertical (Z), east (E) and north (N) to longitudinal (L), radial (Q) and tangential (T) components of motion. Note that the method 'rotate' from ``obspy.core.stream.Stream`` is used for the rotation ``'ZNE->ZRT'`` and ``'ZNE->LQT'``. Rotation ``'ZNE->PVH'`` is implemented separately here due to different conventions. Parameters ---------- vp : float P-wave velocity at surface (km/s) vs : float S-wave velocity at surface (km/s) align : str Alignment of coordinate system for rotation ('ZRT', 'LQT', or 'PVH') Returns ------- rotated : bool Whether or not the object has been rotated """ if not self.meta.accept: return if self.meta.rotated: print("Data have been rotated already - continuing") return # Use default values from meta data if arguments are not specified if not align: align = self.meta.align if align == 'ZNE': from obspy.signal.rotate import rotate2zne # Copy traces trZ = self.data.select(component='Z')[0].copy() trN = self.data.select(component='1')[0].copy() trE = self.data.select(component='2')[0].copy() azim = self.sta.azcorr # Try EBS with left handed system Z, N, E = rotate2zne(trZ.data, 0., -90., trN.data, azim, 0., trE.data, azim + 90., 0.) # Z, N, E = rotate2zne(trZ.data, 0., -90., trN.data, # azim, 0., trE.data, azim+90., 0.) trN.data = N trE.data = E # Update stats of streams trN.stats.channel = trN.stats.channel[:-1] + 'N' trE.stats.channel = trE.stats.channel[:-1] + 'E' self.data = Stream(traces=[trZ, trN, trE]) elif align == 'ZRT': self.data.rotate('NE->RT', back_azimuth=self.meta.baz) self.meta.align = align self.meta.rotated = True elif align == 'LQT': self.data.rotate('ZNE->LQT', back_azimuth=self.meta.baz, inclination=self.meta.inc) for tr in self.data: if tr.stats.channel.endswith('Q'): tr.data = -tr.data self.meta.align = align self.meta.rotated = True elif align == 'PVH': # First rotate to ZRT self.data.rotate('NE->RT', back_azimuth=self.meta.baz) # Copy traces trP = self.data.select(component='Z')[0].copy() trV = self.data.select(component='R')[0].copy() trH = self.data.select(component='T')[0].copy() slow = self.meta.slow if not vp: vp = self.meta.vp if not vs: vs = self.meta.vs # Vertical slownesses # P vertical slowness qp = np.sqrt(1. / vp / vp - slow * slow) # S vertical slowness qs = np.sqrt(1. / vs / vs - slow * slow) # Elements of rotation matrix m11 = slow * vs * vs / vp m12 = -(1. - 2. * vs * vs * slow * slow) / (2. * vp * qp) m21 = (1. - 2. * vs * vs * slow * slow) / (2. * vs * qs) m22 = slow * vs # Rotation matrix rot = np.array([[-m11, m12], [-m21, m22]]) # Vector of Radial and Vertical r_z = np.array([trV.data, trP.data]) # Rotation vec = np.dot(rot, r_z) # Extract P and SV, SH components trP.data = vec[0, :] trV.data = vec[1, :] trH.data = -trH.data / 2. # Update stats of streams trP.stats.channel = trP.stats.channel[:-1] + 'P' trV.stats.channel = trV.stats.channel[:-1] + 'V' trH.stats.channel = trH.stats.channel[:-1] + 'H' # Over-write data attribute self.data = Stream(traces=[trP, trV, trH]) self.meta.align = align self.meta.rotated = True else: raise (Exception("incorrect 'align' argument"))
taper_fraction=0.05, pre_filt=pre_filt, inventory=inv) sta = inv[0][0] azs = [] dips = [] trs = [] channels = ['BHU', 'BHV', 'BHW'] for chn in channels: chndata = sta.select(channel=chn)[0] print('CHNDATA--------------------------------') print(chndata) azs.append(chndata.azimuth) dips.append(chndata.dip) from obspy.signal.rotate import rotate2zne (z, n, e) = rotate2zne(st_rem1[0], azs[0], dips[0], st_rem1[1], azs[1], dips[1], st_rem1[2], azs[2], dips[2]) from scipy import signal lenz = len(z) alp = 5e-2 window = signal.tukey(len(z), alpha=alp) z = z * window n = n * window e = e * window st_new1 = st_rem1.copy() st_new1[0].data = z st_new1[0].stats.channel = 'BHZ' st_new1[1].data = n st_new1[1].stats.channel = 'BHN' st_new1[2].data = e st_new1[2].stats.channel = 'BHE' print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')
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 rotate_components(wfstream, metadata=None): """rotates components if orientation code is numeric. azimut and dip are fetched from metadata""" try: # indexing fails if metadata is None metadata[0] except: if verbosity: msg = 'Warning: could not rotate traces since no metadata was given\nset Inventory file!' print(msg) return wfstream if metadata[0] is None: # sometimes metadata is (None, (None,)) if verbosity: msg = 'Warning: could not rotate traces since no metadata was given\nCheck inventory directory!' print(msg) return wfstream else: parser = metadata[1] def get_dip_azimut(parser, trace_id): """gets azimut and dip for a trace out of the metadata parser""" dip = None azimut = None try: blockettes = parser._select(trace_id) except SEEDParserException as e: print(e) raise ValueError for blockette_ in blockettes: if blockette_.id != 52: continue dip = blockette_.dip azimut = blockette_.azimuth break if dip is None or azimut is None: error_msg = 'Dip and azimuth not available for trace_id {}'.format( trace_id) raise ValueError(error_msg) return dip, azimut trace_ids = [trace.id for trace in wfstream] for trace_id in trace_ids: orientation = trace_id[-1] if orientation.isnumeric(): # misaligned channels have a number as orientation azimuts = [] dips = [] for trace_id in trace_ids: try: dip, azimut = get_dip_azimut(parser, trace_id) except ValueError as e: print(e) print( 'Failed to rotate station {}, no azimuth or dip available in metadata' .format(trace_id)) return wfstream azimuts.append(azimut) dips.append(dip) # to rotate all traces must have same length wfstream = trim_station_components(wfstream, trim_start=True, trim_end=True) z, n, e = rotate2zne(wfstream[0], azimuts[0], dips[0], wfstream[1], azimuts[1], dips[1], wfstream[2], azimuts[2], dips[2]) print('check4rotated: rotated station {} to ZNE'.format( trace_id)) z_index = dips.index(min( dips)) # get z-trace index (dip is measured from 0 to -90 wfstream[z_index].data = z wfstream[z_index].stats.channel = wfstream[ z_index].stats.channel[0:-1] + 'Z' del trace_ids[z_index] for trace_id in trace_ids: dip, az = get_dip_azimut(parser, trace_id) trace = wfstream.select(id=trace_id)[0] if az > 315 and az <= 45 or az > 135 and az <= 225: trace.data = n trace.stats.channel = trace.stats.channel[0:-1] + 'N' elif az > 45 and az <= 135 or az > 225 and az <= 315: trace.data = e trace.stats.channel = trace.stats.channel[0:-1] + 'E' break else: continue return wfstream
except Exception: print('Missing data for station: ',str(sta)) continue H1azi = ori.loc[sta]['H1azi'] for itr in range(0,len(st)): if st[itr].stats.channel == H1comp: h1 = st[itr].data 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()
# Process the traces # st.detrend(type='demean') st.detrend(type='linear') st.decimate(factor=int(st[0].stats.sampling_rate), no_filter=True) # Scale to mm for tr in st: tr.data = tr.data * 1000 # Rotate to real NEZ ch1_azimuth, ch1_dip, = get_channel_orientation(args.t, args.n, args.s, args.l, args.d, args.c[0]) ch2_azimuth, ch2_dip, = get_channel_orientation(args.t, args.n, args.s, args.l, args.d, args.c[1]) ch3_azimuth, ch3_dip, = get_channel_orientation(args.t, args.n, args.s, args.l, args.d, args.c[2]) st[2].data, st[0].data, st[1].data = rotate2zne(st[0].data, ch1_azimuth, ch1_dip, st[1].data, ch2_azimuth, ch2_dip, st[2].data, ch3_azimuth, ch3_dip, inverse=False) # # Make a time array # time = np.arange(st[0].stats.npts) time = time / st[0].stats.sampling_rate # # Add zero padding for plotting # time = np.concatenate((np.zeros([trail-1]), time)) for tr in st: tr.data = np.concatenate((np.zeros([trail-1]), tr.data))
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 test_with_real_data(self): # Filtered and downsampled test data with two co-located # seismometers on a step table. One (UVW) in Galperin configuration, # the other (XYZ) oriented 25 degree towards counter-clockwise from # North. # # Original data can be found here: # http://examples.obspy.org/step_table_galperin_and_xyz.mseed # # Picture of setup: # http://examples.obspy.org/step_table_galperin_and_xyz.jpg u = np.array([ -887.77005805, 7126.9690531, 48436.17065483, 138585.24660557, 220190.69362083, 179040.5715419, -21365.23030094, -253885.25529288, -344888.20815164, -259362.36082208, -117476.30748613, - 42988.81966958, -45995.43307308, -57130.87444412, -30545.75344533, 16298.87665025]) v = np.array([ 2.33308511e+02, 8.16259596e+03, 5.11074487e+04, 1.48229541e+05, 2.41322335e+05, 2.08201013e+05, 4.93732289e+03, -2.39867750e+05, -3.44167596e+05, -2.66558032e+05, -1.27714987e+05, -5.54712804e+04, -6.19973652e+04, -7.66740787e+04, -5.17925310e+04, -4.71673443e+03]) w = np.array([ 1692.48532892, 9875.6136413, 53089.61423663, 149373.52749023, 240009.30157128, 204362.69005767, 1212.47406863, -239380.57384624, -336783.01040666, -252884.65411222, -110766.44577398, -38182.18142102, -45729.92956198, -61691.87092415, -38434.81993441, 6224.73096858]) x = np.array([ -1844.85832046, -1778.44974024, -2145.6117388, -4325.27560474, -8278.1836905, -10842.53378841, -8565.12113951, -2024.53838011, 4439.22322848, 7340.96354878, 7081.65449722, 6303.91640198, 6549.98692684, 7223.59663617, 7133.72073748, 6068.56702479]) y = np.array([ -242.70568894, -458.3864756, -351.75925077, 2142.51669733, 8287.98182002, 15822.24351111, 20151.78532927, 18511.90136103, 12430.22438956, 5837.66044337, 1274.9580289, -1597.06115226, -4331.40686142, -7529.87533286, -10544.34374306, -12656.77586305]) z = np.array([ 5.79050980e+02, 1.45190734e+04, 8.85582128e+04, 2.53690907e+05, 4.08578800e+05, 3.45046937e+05, -8.15914926e+03, -4.26449298e+05, -5.97207861e+05, -4.53464470e+05, -2.07176498e+05, -7.94526512e+04, -8.95206215e+04, -1.14008287e+05, -7.05797830e+04, 1.01175730e+04]) # Component orientations. u = (u, 90.0, -(90.0 - 54.7), "U") v = (v, 330.0, -(90.0 - 54.7), "V") w = (w, 210.0, -(90.0 - 54.7), "W") x = (x, 65.0, 0.0, "X") y = (y, 335.0, 0.0, "Y") z = (z, 0.0, -90.0, "Z") # Any three should result in the same ZNE. success_count = 0 failure_count = 0 for a, b, c in itertools.permutations([x, y, z, u], 3): # Except if "X" and "Y" are both part of it because they don't # really contain any data (vertical step table). if set(["X", "Y"]).issubset(set([a[-1], b[-1], c[-1]])): failure_count += 1 continue z_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[0], rtol=1E-5) success_count += 1 # Sanity check that it fails for slightly different rotations. z_new, _, _ = rotate2zne( a[0], a[1] + 1.5, a[2] - 1.5, b[0], b[1] - 0.7, b[2] + 1.2, c[0], c[1] + 1.0, c[2] - 0.4) with self.assertRaises(AssertionError): np.testing.assert_allclose(z_new, z[0], rtol=1E-5) self.assertEqual(success_count, 12) self.assertEqual(failure_count, 12)
def data_process(event2find): print('Running code for: Event ' + event2find + ' and ' + comp) for i in range(0, len(event)): event1 = str(event[i]) if event1 == event2find: a = i time_1 = str(eventtime[a]) t1l = len(time_1) - 3 time_2 = time_1 class_1 = str(eventclass[a]) c1l = len(class_1) - 3 class_2 = class_1 quality_1 = str(quality[a]) q1l = len(quality_1) - 3 quality_2 = quality_1 print('Event: ' + event2find) print('Datetime of the event: ' + time_2) print('Class: ' + class_2) print('Quality: ' + quality_2) from obspy import UTCDateTime time = UTCDateTime(time_2) starttime = time - 60 * 30 print(starttime) endtime = time + 60 * 90 print(endtime) net = 'XB' sta = 'ELYSE' loc = '02' chan = 'BH*' url = ('https://ws.seis-insight.eu/fdsnws/dataselect/1/query?network=' + net + '&station=' + sta + '&startTime=' + str(starttime) + '&endTime=' + str(endtime) + '&location=*&channel=' + chan) r = requests.get(url, auth=(username, password)) filename = ('fdsnws_msds.mseed') if r.status_code == 200: with open(filename, 'wb') as out: for bits in r.iter_content(): out.write(bits) import obspy from obspy import read st = read('fdsnws_msds.mseed') print(st) for tr in st.select(component='U'): st.merge(tr) print('----------------------') print('Streams after merging') print('----------------------') print(st) timeE1 = st[0].stats.starttime timeN1 = st[1].stats.starttime timeZ1 = st[2].stats.starttime stime = max(timeE1, timeN1, timeZ1) timeEe = st[0].stats.endtime timeNe = st[1].stats.endtime timeZe = st[2].stats.endtime etime = min(timeEe, timeNe, timeZe) st[0].trim(stime, etime) st[1].trim(stime, etime) st[2].trim(stime, etime) print('----------------------') print('Streams after trimming') print('----------------------') print(st) from obspy import read_inventory inv = obspy.read_inventory('dataless.XB.ELYSE.seed') st_rem1 = st.copy() pre_filt = [0.005, 0.01, 8, 10] #for 20 Hz data st_rem1.remove_response(output=comp, taper_fraction=0.05, pre_filt=pre_filt, inventory=inv) sta = inv[0][0] azs = [] dips = [] trs = [] channels = ['BHU', 'BHV', 'BHW'] for chn in channels: chndata = sta.select(channel=chn)[0] print('CHNDATA--------------------------------') print(chndata) azs.append(chndata.azimuth) dips.append(chndata.dip) from obspy.signal.rotate import rotate2zne (z, n, e) = rotate2zne(st_rem1[0], azs[0], dips[0], st_rem1[1], azs[1], dips[1], st_rem1[2], azs[2], dips[2]) from scipy import signal lenz = len(z) alp = 5e-2 window = signal.tukey(len(z), alpha=alp) z = z * window n = n * window e = e * window st_new1 = st_rem1.copy() st_new1[0].data = z st_new1[0].stats.channel = 'BHZ' st_new1[1].data = n st_new1[1].stats.channel = 'BHN' st_new1[2].data = e st_new1[2].stats.channel = 'BHE' print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[0].stats) print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[1].stats) print('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') print(st_new1[2].stats) import os path = ('Treated/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('Treated/' + class_2 + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('Treated/' + class_2 + '/' + quality_2 + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) path = ('Treated/' + class_2 + '/' + quality_2 + '/' + event2find + '/') check = os.path.isdir(path) if check == False: os.mkdir(path) filename1 = (path + '/' + event2find + '_' + comp + '.mseed') st_new1.write(filename1, format='MSEED') targetfile = (path + '/' + event2find + '.mseed') from shutil import copyfile copyfile('fdsnws_msds.mseed', targetfile)
def rotation(stream, method="NE->RT", acc_type="event"): """ Rotatation. :param stream: obspy stream to be rotated :param method: "NE->RT" or "ZNE->LQT" :param acc_type: "event", "noise" :return stream: obspy stream after rotation. .. note:: The keywords `component_azimuth` and `component_inclination` must be given in the stats. Currently, only acc_type="event" are well debugged. The input 3-component data should be in the roughly same periods or time window. """ rot_stream = Stream() # function to extract 3-component stream. # if the data are given event the data, then use onset as the key word to find the 3-component data if acc_type == "event": key = "onset" elif acc_type == "noise": key = "starttime" def iter3c(stream): return IterMultipleComponents(stream, key=key, number_components=(2, 3)) for st3c in iter3c(stream): tmin, tmax = _find_start_end_time(stream=st3c) if tmin > tmax: continue st3c.trim(starttime=tmin, endtime=tmax) # handling the borehole components 1, 2, Z or 1, 2, 3. comp = [] for tr in st3c: comp.append(tr.stats.channel[-1]) comp.sort() cc = "".join(comp) if cc == "12Z": cc = "Z12" # rotate2zne if cc in ["123", "Z12"]: zne = rotate2zne(st3c[0].data, st3c[0].stats.component_azimuth, st3c[0].stats.component_inclination, st3c[1].data, st3c[1].stats.component_azimuth, st3c[1].stats.component_inclination, st3c[2].data, st3c[2].stats.component_azimuth, st3c[2].stats.component_inclination) for tr, new_data, component in zip(st3c, zne, "ZNE"): tr.data = new_data tr.stats.channel = tr.stats.channel[:-1] + component # rotate to various coordinates st3c.rotate(method=method) rot_stream += st3c return rot_stream