def prepare(self): # initialize parameters self.Fs = self.config['wavefield_sampling_rate'] self.npts = int(self.config['wavefield_duration'] * self.Fs) self.ntraces = self.sourcegrid.shape[-1] self.data_quantity = self.config['synt_data'] if self.config['wavefield_domain'] == 'fourier': self.fdomain = True if self.npts % 2 == 1: self.npad = 2 * self.npts - 2 else: self.npad = 2 * self.npts elif self.config['wavefield_domain'] == 'time': self.fdomain = False self.npad = next_fast_len(2 * self.npts - 1) else: raise ValueError('Unknown domain {}.'.format( self.config['wavefield_domain'])) self.freq = np.fft.rfftfreq(self.npad, d=1.0 / self.Fs) # Apply a filter if self.config['wavefield_filter'] is not None: freq_nyq = self.Fs / 2.0 # Nyquist if freq_nyq < self.config['wavefield_filter'][1]: warn("Selected upper freq > Nyquist, \ reset to 95\% of Nyquist freq.") freq_minres = 1. / self.config['wavefield_duration'] # lowest resolved freq_max = min(0.999 * freq_nyq, self.config['wavefield_filter'][1]) freq_min = max(freq_minres, self.config['wavefield_filter'][0]) f0 = freq_min / freq_nyq f1 = freq_max / freq_nyq self.filter = butter(4, [f0, f1], 'bandpass') else: self.filter = None # if using instaseis: Find and open database if self.config['wavefield_type'] == 'instaseis': path_to_db = self.config['wavefield_path'] self.db = instaseis.open_db(path_to_db) if self.db.info['length'] < self.npts / self.Fs: warn("Resetting wavefield duration to axisem database length.") fsrc = instaseis.ForceSource(latitude=0.0, longitude=0.0, f_r=1.0) rec = instaseis.Receiver(latitude=0.0, longitude=0.0) test = self.db.get_seismograms(source=fsrc, receiver=rec, dt=1. / self.Fs) self.npts = test[0].stats.npts
def get_ns(wf1, source_conf, insta): # Nr of time steps in traces if insta: # get path to instaseis db #ToDo: ugly. dbpath = json.load( open(os.path.join(source_conf['project_path'], 'config.json')))['wavefield_path'] # open db = instaseis.open_db(dbpath) # get a test seismogram to determine... stest = db.get_seismograms(source=instaseis.ForceSource(latitude=0.0, longitude=0.0), receiver=instaseis.Receiver(latitude=10., longitude=0.0), dt=1. / source_conf['sampling_rate'])[0] nt = stest.stats.npts Fs = stest.stats.sampling_rate else: with WaveField(wf1) as wf1: nt = int(wf1.stats['nt']) Fs = round(wf1.stats['Fs'], 8) # Necessary length of zero padding for carrying out # frequency domain correlations/convolutions n = next_fast_len(2 * nt - 1) # Number of time steps for synthetic correlation n_lag = int(source_conf['max_lag'] * Fs) if nt - 2 * n_lag <= 0: click.secho('Resetting maximum lag to %g seconds: Synthetics are too\ short for a maximum lag of %g seconds.' % (nt // 2 / Fs, n_lag / Fs)) n_lag = nt // 2 n_corr = 2 * n_lag + 1 return nt, n, n_corr, Fs
def get_ns(all_conf, insta=False): # Nr of time steps in traces if insta: # get path to instaseis db dbpath = all_conf.config['wavefield_path'] # open db = instaseis.open_db(dbpath) # get a test seismogram to determine... stest = db.get_seismograms(source=instaseis.ForceSource(latitude=0.0, longitude=0.), receiver=instaseis.Receiver(latitude=10., longitude=0.), dt=1. / all_conf.config ['wavefield_sampling_rate'])[0] nt = stest.stats.npts Fs = stest.stats.sampling_rate else: any_wavefield = glob(os.path.join(all_conf.config['project_path'], 'greens', '*.h5'))[-1] with WaveField(any_wavefield) as wf1: nt = int(wf1.stats['nt']) Fs = round(wf1.stats['Fs'], 8) n = wf1.stats['npad'] # # Necessary length of zero padding # # for carrying out frequency domain correlations/convolutions # n = next_fast_len(2 * nt - 1) # Number of time steps for synthetic correlation n_lag = int(all_conf.source_config['max_lag'] * Fs) if nt - 2 * n_lag <= 0: n_lag_old = n_lag n_lag = nt // 2 warn('Resetting maximum lag to %g seconds:\ Synthetics are too short for %g seconds.' % (n_lag / Fs, n_lag_old / Fs)) n_corr = 2 * n_lag + 1 return nt, n, n_corr, Fs
def g1g2_kern(wf1str, wf2str, kernel, adjt, src, source_conf, insta): measr_conf = json.load( open(os.path.join(source_conf['source_path'], 'measr_config.json'))) bandpass = measr_conf['bandpass'] if bandpass == None: filtcnt = 1 elif type(bandpass) == list: if type(bandpass[0]) != list: filtcnt = 1 else: filtcnt = len(bandpass) ntime, n, n_corr, Fs = get_ns(wf1str, source_conf, insta) # use a one-sided taper: The seismogram probably has a non-zero end, # being cut off whereever the solver stopped running. taper = cosine_taper(ntime, p=0.01) taper[0:ntime // 2] = 1.0 ######################################################################## # Prepare filenames and adjoint sources ######################################################################## filenames = [] adjt_srcs = [] adjt_srcs_cnt = 0 for ix_f in range(filtcnt): filename = kernel + '.{}.npy'.format(ix_f) filenames.append(filename) #if os.path.exists(filename): # continue f = Stream() for a in adjt: adjtfile = a + '*.{}.sac'.format(ix_f) adjtfile = glob(adjtfile) try: f += read(adjtfile[0])[0] f[-1].data = my_centered(f[-1].data, n_corr) adjt_srcs_cnt += 1 except IndexError: print('No adjoint source found: {}\n'.format(a)) break adjt_srcs.append(f) ######################################################################## # Compute the kernels ######################################################################## with NoiseSource(src) as nsrc: ntraces = nsrc.src_loc[0].shape[0] if insta: # open database dbpath = json.load( open(os.path.join(source_conf['project_path'], 'config.json')))['wavefield_path'] # open and determine Fs, nt db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1str) wf2 = WaveField(wf2str) kern = np.zeros((filtcnt, ntraces, len(adjt))) ######################################################################## # Loop over locations ######################################################################## for i in range(ntraces): # noise source spectrum at this location # For the kernel, this contains only the basis functions of the # spectrum without weights; might still be location-dependent, # for example when constraining sensivity to ocean S = nsrc.get_spect(i) if S.sum() == 0.: # The spectrum has 0 phase so only checking absolute value here continue #################################################################### # Get synthetics #################################################################### if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) s1 = np.ascontiguousarray( db.get_seismograms( source=fsrc, receiver=rec1, dt=1. / source_conf['sampling_rate'])[0].data * taper) s2 = np.ascontiguousarray( db.get_seismograms( source=fsrc, receiver=rec2, dt=1. / source_conf['sampling_rate'])[0].data * taper) else: s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) g1g2_tr = np.multiply(np.conjugate(spec1), spec2) c = np.multiply(g1g2_tr, S) ####################################################################### # Get Kernel at that location ####################################################################### corr_temp = my_centered(np.fft.ifftshift(np.fft.irfft(c, n)), n_corr) ####################################################################### # Apply the 'adjoint source' ####################################################################### for ix_f in range(filtcnt): f = adjt_srcs[ix_f] if f == None: continue for j in range(len(f)): delta = f[j].stats.delta kern[ix_f, i, j] = np.dot(corr_temp, f[j].data) * delta #elif measr_conf['mtype'] in ['envelope']: # if j == 0: # corr_temp_h = corr_temp # print(corr_temp_h) # if j == 1: # corr_temp_h = hilbert(corr_temp) # print(corr_temp_h) # # kern[ix_f,i,j] = np.dot(corr_temp,f[j].data) * delta if i % 50000 == 0: print("Finished {} source locations.".format(i)) if not insta: wf1.file.close() wf2.file.close() for ix_f in range(filtcnt): filename = filenames[ix_f] if kern[ix_f, :, :].sum() != 0: np.save(filename, kern[ix_f, :, :]) return ()
def green_from_instaseis(self, station): # set some parameters lat_sta = station['lat'] lon_sta = station['lon'] lat_sta = geograph_to_geocent(float(lat_sta)) lon_sta = float(lon_sta) rec = instaseis.Receiver(latitude=lat_sta, longitude=lon_sta) point_f = float(self.config['wavefield_point_force']) channel = self.config['wavefield_channel'] station_id = station['net'] + '.' + station['sta'] + '..MX' + channel if self.config['verbose']: print(station_id) if channel == 'Z': c_index = 0 elif channel == 'R': c_index = 1 elif channel == 'T': c_index = 2 else: raise ValueError("Unknown channel: %s, choose R, T, Z" % channel) # initialize the file f_out = os.path.join(self.wf_path, station_id + '.h5') with h5py.File(f_out, "w") as f: # DATASET NR 1: STATS stats = f.create_dataset('stats', data=(0,)) stats.attrs['reference_station'] = station['sta'] stats.attrs['data_quantity'] = self.data_quantity stats.attrs['ntraces'] = self.ntraces stats.attrs['Fs'] = self.Fs stats.attrs['nt'] = int(self.npts) stats.attrs['npad'] = self.npad if self.fdomain: stats.attrs['fdomain'] = True else: stats.attrs['fdomain'] = False # DATASET NR 2: Source grid f.create_dataset('sourcegrid', data=self.sourcegrid) # DATASET Nr 3: Seismograms itself if self.fdomain: traces = f.create_dataset('data', (self.ntraces, self.npts + 1), dtype=np.complex64) else: traces = f.create_dataset('data', (self.ntraces, self.npts), dtype=np.float32) for i in range(self.ntraces): if i % 1000 == 0 and i > 0 and self.config['verbose']: print('Converted %g of %g traces' % (i, self.ntraces)) lat_src = geograph_to_geocent(self.sourcegrid[1, i]) lon_src = self.sourcegrid[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=point_f) if self.config['synt_data'] == 'DIS': values = self.db.get_seismograms(source=fsrc, receiver=rec, dt=1. / self.Fs) elif self.config['synt_data'] == 'VEL': values = self.db.get_seismograms(source=fsrc, receiver=rec, dt=1. / self.Fs, kind='velocity') elif self.config['synt_data'] == 'ACC': values = self.db.get_seismograms(source=fsrc, receiver=rec, dt=1. / self.Fs, kind='acceleration') else: raise ValueError('Unknown data quantity. \ Choose DIS, VEL or ACC in configuration.') if channel in ['R', 'T']: baz = gps2dist_azimuth(lat_src, lon_src, lat_sta, lon_sta)[2] values.rotate('NE->RT', baz) if self.filter is not None: trace = lfilter(*self.filter, x=values[c_index].data) else: trace = values[c_index].data if self.fdomain: trace_fd = np.fft.rfft(trace[0: self.npts], n=self.npad) traces[i, :] = trace_fd else: traces[i, :] = trace[0: self.npts] return()
def compute_correlation(input_files, all_conf, nsrc, all_ns, taper, insta=False): """ Compute noise cross-correlations from two .h5 'wavefield' files. Noise source distribution and spectrum is given by starting_model.h5 It is assumed that noise sources are delta-correlated in space. Metainformation: Include the reference station names for both stations from wavefield files, if possible. Do not include geographic information from .csv file as this might be error-prone. Just add the geographic info later if needed. """ wf1, wf2 = input_files ntime, n, n_corr, Fs = all_ns ntraces = nsrc.src_loc[0].shape[0] correlation = np.zeros(n_corr) if insta: # open database dbpath = all_conf.config['wavefield_path'] # open db = instaseis.open_db(dbpath) # get receiver locations station1 = wf1[0] station2 = wf2[0] lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1) wf2 = WaveField(wf2) station1 = wf1.stats['reference_station'] station2 = wf2.stats['reference_station'] # Make sure all is consistent if False in (wf1.sourcegrid[1, 0:10] == wf2.sourcegrid[1, 0:10]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[1, -10:] == wf2.sourcegrid[1, -10:]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[0, -10:] == nsrc.src_loc[0, -10:]): raise ValueError("Wave field and source not consistent.") # Loop over source locations print_each_n = max(5, round(max(ntraces // 5, 1), -1)) for i in range(ntraces): # noise source spectrum at this location S = nsrc.get_spect(i) if S.sum() == 0.: # If amplitude is 0, continue. (Spectrum has 0 phase anyway.) continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) Fs = all_conf.config['wavefield_sampling_rate'] s1 = db.get_seismograms(source=fsrc, receiver=rec1, dt=1. / Fs)[0].data * taper s2 = db.get_seismograms(source=fsrc, receiver=rec2, dt=1. / Fs)[0].data * taper s1 = np.ascontiguousarray(s1) s2 = np.ascontiguousarray(s2) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: if not wf1.fdomain: # read Green's functions s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) # Fourier transform for greater ease of convolution spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: spec1 = np.ascontiguousarray(wf1.data[i, :]) spec2 = np.ascontiguousarray(wf2.data[i, :]) # convolve G1G2 g1g2_tr = np.multiply(np.conjugate(spec1), spec2) # convolve noise source c = np.multiply(g1g2_tr, S) # transform back correlation += my_centered(np.fft.fftshift(np.fft.irfft(c, n)), n_corr) * nsrc.surf_area[i] # occasional info if i % print_each_n == 0 and all_conf.config['verbose']: print("Finished {} of {} source locations.".format(i, ntraces)) # end of loop over all source locations ####################################### return(correlation, station1, station2)
def test_seismogram_extraction(all_remote_dbs): """ Test the seismogram extraction from local and remote databases. """ # Remote and local database. r_db = all_remote_dbs l_db = instaseis.open_db(r_db._client.filepath) # Mock responses to get the tornado testing to work. _add_callback(r_db._client) source = instaseis.Source( latitude=4.0, longitude=3.0, depth_in_m=0, m_rr=4.71e17, m_tt=3.81e17, m_pp=-4.74e17, m_rt=3.99e17, m_rp=-8.05e17, m_tp=-1.23e17, ) receiver = instaseis.Receiver(latitude=10.0, longitude=20.0, depth_in_m=None) components = r_db.available_components kwargs = {"source": source, "receiver": receiver, "components": components} _compare_streams(r_db, l_db, kwargs) # Test velocity and acceleration. kwargs = { "source": source, "receiver": receiver, "components": components, "kind": "velocity", } _compare_streams(r_db, l_db, kwargs) kwargs = { "source": source, "receiver": receiver, "components": components, "kind": "acceleration", } _compare_streams(r_db, l_db, kwargs) # Test remove source shift. kwargs = { "source": source, "receiver": receiver, "components": components, "remove_source_shift": False, } _compare_streams(r_db, l_db, kwargs) # Test resampling. kwargs = { "source": source, "receiver": receiver, "components": components, "dt": 1.0, "kernelwidth": 6, } _compare_streams(r_db, l_db, kwargs) # Test force source. if "displ_only" in r_db._client.filepath: source = instaseis.ForceSource( latitude=89.91, longitude=0.0, depth_in_m=12000, f_r=1.23e10, f_t=2.55e10, f_p=1.73e10, ) kwargs = {"source": source, "receiver": receiver} _compare_streams(r_db, l_db, kwargs) # Fix receiver depth, network, and station codes. receiver = instaseis.Receiver( latitude=10.0, longitude=20.0, depth_in_m=0.0, station="ALTM", network="BW", ) kwargs = {"source": source, "receiver": receiver, "components": components} _compare_streams(r_db, l_db, kwargs)
def test_seismogram_extraction(syngine_client): """ Test the seismogram extraction from local and syngine databases. """ # syngine and local database. s_db = syngine_client l_db = instaseis.open_db(db_path) source = instaseis.Source( latitude=4.0, longitude=3.0, depth_in_m=0, m_rr=4.71e17, m_tt=3.81e17, m_pp=-4.74e17, m_rt=3.99e17, m_rp=-8.05e17, m_tp=-1.23e17, ) receiver = instaseis.Receiver(latitude=10.0, longitude=20.0, depth_in_m=None) kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], } _compare_streams(s_db, l_db, kwargs) # Test velocity and acceleration. kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], "kind": "velocity", } _compare_streams(s_db, l_db, kwargs) kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], "kind": "acceleration", } _compare_streams(s_db, l_db, kwargs) # Test remove source shift. kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], "remove_source_shift": False, } _compare_streams(s_db, l_db, kwargs) # Test resampling. kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], "dt": 1.0, "kernelwidth": 6, } _compare_streams(s_db, l_db, kwargs) # Force sources currently raise an error. source = instaseis.ForceSource( latitude=89.91, longitude=0.0, depth_in_m=12000, f_r=1.23e10, f_t=2.55e10, f_p=1.73e10, ) kwargs = {"source": source, "receiver": receiver} with pytest.raises(ValueError) as e: _compare_streams(s_db, l_db, kwargs) assert e.value.args[0] == ( "The Syngine Instaseis client does currently not " "support force sources. You can still download " "data from the Syngine service for force " "sources manually.") # Test less components and a latitude of 45 degrees to have the maximal # effect of geocentric vs geographic coordinates. source = instaseis.Source( latitude=45.0, longitude=3.0, depth_in_m=0, m_rr=4.71e17, m_tt=3.81e17, m_pp=-4.74e17, m_rt=3.99e17, m_rp=-8.05e17, m_tp=-1.23e17, ) receiver = instaseis.Receiver(latitude=-45.0, longitude=20.0, depth_in_m=None) kwargs = { "source": source, "receiver": receiver, "components": ["Z", "N", "E", "R", "T"], } _compare_streams(s_db, l_db, kwargs)
def compute_kernel(input_files, output_file, all_conf, nsrc, all_ns, taper, insta=False): ntime, n, n_corr, Fs = all_ns wf1, wf2, adjt = input_files ######################################################################## # Prepare filenames and adjoint sources ######################################################################## adjt_srcs = open_adjoint_sources(all_conf, adjt, n_corr) if None in adjt_srcs: return (None) else: if all_conf.config["verbose"]: print("========================================") print("Computing: " + output_file) # Uniform spatial weights. (current model is in the adjoint source) nsrc.distr_basis = np.ones(nsrc.distr_basis.shape) ntraces = nsrc.src_loc[0].shape[0] # [comp1, comp2] = [wf1, wf2] # keep these strings in case need to be rotated if insta: # open database dbpath = all_conf.config['wavefield_path'] # open and determine Fs, nt db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1) wf2 = WaveField(wf2) # Make sure all is consistent if False in (wf1.sourcegrid[1, 0:10] == wf2.sourcegrid[1, 0:10]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[1, -10:] == wf2.sourcegrid[1, -10:]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[0, -10:] == nsrc.src_loc[0, -10:]): raise ValueError("Wave field and source not consistent.") kern = np.zeros( (nsrc.spect_basis.shape[0], all_conf.filtcnt, ntraces, len(adjt))) if all_conf.source_config["rotate_horizontal_components"]: tempfile = output_file + ".h5_temp" temp = wf1.copy_setup(tempfile, ntraces=ntraces, nt=n_corr) map_temp_datasets = {0: temp.data} for ix_spec in range(1, nsrc.spect_basis.shape[0]): dtmp = temp.file.create_dataset('data{}'.format(ix_spec), temp.data.shape, dtype=np.float32) map_temp_datasets[ix_spec] = dtmp # Loop over locations print_each_n = max(5, round(max(ntraces // 5, 1), -1)) # preload wavefield and spectrum S_all = nsrc.get_spect_all() wf1_data = np.asarray(wf1.data) wf2_data = np.asarray(wf2.data) for i in range(ntraces): # noise source spectrum at this location # For the kernel, this contains only the basis functions of the # spectrum without weights; might still be location-dependent, # for example when constraining sensivity to ocean #S = nsrc.get_spect(i) S = S_all[i, :] if S.sum() == 0.: # The spectrum has 0 phase so only checking # absolute value here continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) dt = 1. / all_conf.source_config['sampling_rate'] s1 = db.get_seismograms(source=fsrc, receiver=rec1, dt=dt)[0].data * taper s1 = np.ascontiguousarray(s1) s2 = db.get_seismograms(source=fsrc, receiver=rec2, dt=dt)[0].data * taper s2 = np.ascontiguousarray(s2) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: if not wf1.fdomain: s1 = np.ascontiguousarray(wf1_data[i, :] * taper) s2 = np.ascontiguousarray(wf2_data[i, :] * taper) # if horizontal component rotation: perform it here # more convenient before FFT to avoid additional FFTs spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: spec1 = wf1_data[i, :] spec2 = wf2_data[i, :] g1g2_tr = np.multiply(np.conjugate(spec1), spec2) # spectrum for ix_spec in range(nsrc.spect_basis.shape[0]): c = np.multiply(g1g2_tr, nsrc.spect_basis[ix_spec, :]) ################################################################### # Get Kernel at that location ################################################################### ctemp = np.fft.fftshift(np.fft.irfft(c, n)) corr_temp = my_centered(ctemp, n_corr) if all_conf.source_config["rotate_horizontal_components"]: map_temp_datasets[ix_spec][i, :] = corr_temp ################################################################### # Apply the 'adjoint source' ################################################################### for ix_f in range(all_conf.filtcnt): f = adjt_srcs[ix_f] if f is None: continue for j in range(len(f)): delta = f[j].stats.delta kern[ix_spec, ix_f, i, j] = np.dot(corr_temp, f[j].data) * delta if i % print_each_n == 0 and all_conf.config['verbose']: print("Finished {} of {} source locations.".format(i, ntraces)) if not insta: wf1.file.close() wf2.file.close() if all_conf.source_config["rotate_horizontal_components"]: temp.file.close() return kern
def g1g2_kern(wf1str, wf2str, kernel, adjt, src, source_conf, insta=False): measr_conf = yaml.safe_load( open(os.path.join(source_conf['source_path'], 'measr_config.yml'))) bandpass = measr_conf['bandpass'] conf = yaml.safe_load( open(os.path.join(source_conf['project_path'], 'config.yml'))) if bandpass is None: filtcnt = 1 elif type(bandpass) == list: if type(bandpass[0]) != list: filtcnt = 1 else: filtcnt = len(bandpass) ntime, n, n_corr, Fs = get_ns(wf1str, source_conf, insta) # use a one-sided taper: The seismogram probably has a non-zero end, # being cut off whereever the solver stopped running. taper = cosine_taper(ntime, p=0.01) taper[0:ntime // 2] = 1.0 ######################################################################## # Prepare filenames and adjoint sources ######################################################################## filenames = [] adjt_srcs = [] for ix_f in range(filtcnt): filename = kernel + '.{}.npy'.format(ix_f) filenames.append(filename) f = Stream() for a in adjt: adjtfile = a + '*.{}.sac'.format(ix_f) adjtfile = glob(adjtfile) try: f += read(adjtfile[0])[0] f[-1].data = my_centered(f[-1].data, n_corr) except IndexError: warn('No adjoint source found: {}\n'.format(a)) if len(f) > 0: adjt_srcs.append(f) else: return () ######################################################################## # Compute the kernels ######################################################################## with NoiseSource(src) as nsrc: # Uniform spatial weights. nsrc.distr_basis = np.ones(nsrc.distr_basis.shape) ntraces = nsrc.src_loc[0].shape[0] if insta: # open database dbpath = conf['wavefield_path'] # open and determine Fs, nt db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1str) wf2 = WaveField(wf2str) # Make sure all is consistent if False in (wf1.sourcegrid[1, 0:10] == wf2.sourcegrid[1, 0:10]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[1, -10:] == wf2.sourcegrid[1, -10:]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[0, -10:] == nsrc.src_loc[0, -10:]): raise ValueError("Wave field and source not consistent.") kern = np.zeros((filtcnt, ntraces, len(adjt))) # Loop over locations print_each_n = max(5, round(max(ntraces // 5, 1), -1)) for i in range(ntraces): # noise source spectrum at this location # For the kernel, this contains only the basis functions of the # spectrum without weights; might still be location-dependent, # for example when constraining sensivity to ocean S = nsrc.get_spect(i) if S.sum() == 0.: # The spectrum has 0 phase so only checking # absolute value here continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) dt = 1. / source_conf['sampling_rate'] s1 = db.get_seismograms(source=fsrc, receiver=rec1, dt=dt)[0].data * taper s1 = np.ascontiguousarray(s1) s2 = db.get_seismograms(source=fsrc, receiver=rec2, dt=dt)[0].data * taper s2 = np.ascontiguousarray(s2) else: s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) g1g2_tr = np.multiply(np.conjugate(spec1), spec2) c = np.multiply(g1g2_tr, S) ####################################################################### # Get Kernel at that location ####################################################################### corr_temp = my_centered(np.fft.fftshift(np.fft.irfft(c, n)), n_corr) ####################################################################### # Apply the 'adjoint source' ####################################################################### for ix_f in range(filtcnt): f = adjt_srcs[ix_f] if f is None: continue for j in range(len(f)): delta = f[j].stats.delta kern[ix_f, i, j] = np.dot(corr_temp, f[j].data) * delta if i % print_each_n == 0 and conf['verbose']: print("Finished {} of {} source locations.".format(i, ntraces)) if not insta: wf1.file.close() wf2.file.close() for ix_f in range(filtcnt): filename = filenames[ix_f] if kern[ix_f, :, :].sum() != 0: np.save(filename, kern[ix_f, :, :]) return ()
# get config source_config=json.load(open('source_config.json')) config = json.load(open('../config.json')) Fs = source_config['sampling_rate'] path_to_db = config['wavefield_path'] channel = source_config['channel'] # read sourcegrid f_sources = np.load('../sourcegrid.npy') ntraces = f_sources.shape[-1] # open the database db = instaseis.open_db(path_to_db) # get: synthetics duration and sampling rate in Hz stest = db.get_seismograms(source=instaseis.ForceSource(latitude=0.0, longitude=0.0),receiver=instaseis.Receiver(latitude=10., longitude=0.0),dt=1./source_config['sampling_rate'])[0] ntimesteps = stest.stats.npts # read station from file stationlist = read_csv('../stationlist.csv') net = stationlist.at[rank,'net'] sta = stationlist.at[rank,'sta'] lat = stationlist.at[rank,'lat'] lon = stationlist.at[rank,'lon'] print(net,sta,lat,lon) # output directory: if rank == 0:
def g1g2_corr(wf1, wf2, corr_file, src, source_conf, insta): """ Compute noise cross-correlations from two .h5 'wavefield' files. Noise source distribution and spectrum is given by starting_model.h5 It is assumed that noise sources are delta-correlated in space. """ #ToDo: check whether to include autocorrs from user (now hardcoded off) #ToDo: Parallel loop(s) #ToDo tests # Metainformation: Include the reference station names for both stations # from wavefield files, if possible. Do not include geographic information # from .csv file as this might be error-prone. Just add the geographic # info later if needed. with NoiseSource(src) as nsrc: ntime, n, n_corr, Fs = get_ns(wf1, source_conf, insta) # use a one-sided taper: The seismogram probably has a non-zero end, # being cut off whereever the solver stopped running. taper = cosine_taper(ntime, p=0.01) taper[0:ntime // 2] = 1.0 ntraces = nsrc.src_loc[0].shape[0] print(taper.shape) correlation = np.zeros(n_corr) if insta: # open database dbpath = json.load( open(os.path.join(source_conf['project_path'], 'config.json')))['wavefield_path'] # open and determine Fs, nt db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1) wf2 = WaveField(wf2) # Loop over source locations for i in range(ntraces): # noise source spectrum at this location S = nsrc.get_spect(i) if S.sum() == 0.: #If amplitude is 0, continue. (Spectrum has 0 phase anyway. ) continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) s1 = np.ascontiguousarray( db.get_seismograms( source=fsrc, receiver=rec1, dt=1. / source_conf['sampling_rate'])[0].data * taper) s2 = np.ascontiguousarray( db.get_seismograms( source=fsrc, receiver=rec2, dt=1. / source_conf['sampling_rate'])[0].data * taper) else: # read Green's functions s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) # Fourier transform for greater ease of convolution spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) # convolve G1G2 g1g2_tr = np.multiply(np.conjugate(spec1), spec2) # convolve noise source c = np.multiply(g1g2_tr, S) # transform back correlation += my_centered(np.fft.ifftshift(np.fft.irfft(c, n)), n_corr) * nsrc.surf_area[i] # occasional info if i % 50000 == 0: print("Finished {} source locations.".format(i)) ###################### end of loop over all source locations ################### if not insta: wf1.file.close() wf2.file.close() # save output trace = Trace() trace.stats.sampling_rate = Fs trace.data = correlation # try to add some meta data try: sta1 = wf1.stats['reference_station'] sta2 = wf2.stats['reference_station'] trace.stats.station = sta1.split('.')[1] trace.stats.network = sta1.split('.')[0] trace.stats.location = sta1.split('.')[2] trace.stats.channel = sta1.split('.')[3] trace.stats.sac = {} trace.stats.sac['kuser0'] = sta2.split('.')[1] trace.stats.sac['kuser1'] = sta2.split('.')[0] trace.stats.sac['kuser2'] = sta2.split('.')[2] trace.stats.sac['kevnm'] = sta2.split('.')[3] except: pass trace.write(filename=corr_file, format='SAC')
def g1g2_corr(wf1, wf2, corr_file, src, source_conf, insta=False): """ Compute noise cross-correlations from two .h5 'wavefield' files. Noise source distribution and spectrum is given by starting_model.h5 It is assumed that noise sources are delta-correlated in space. Metainformation: Include the reference station names for both stations from wavefield files, if possible. Do not include geographic information from .csv file as this might be error-prone. Just add the geographic info later if needed. """ with open(os.path.join(source_conf['project_path'], 'config.yml')) as fh: conf = yaml.safe_load(fh) with NoiseSource(src) as nsrc: ntime, n, n_corr, Fs = get_ns(wf1, source_conf, insta) # use a one-sided taper: The seismogram probably has a non-zero end, # being cut off wherever the solver stopped running. taper = cosine_taper(ntime, p=0.01) taper[0:ntime // 2] = 1.0 ntraces = nsrc.src_loc[0].shape[0] correlation = np.zeros(n_corr) if insta: # open database dbpath = conf['wavefield_path'] # open db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1) wf2 = WaveField(wf2) # Make sure all is consistent if False in (wf1.sourcegrid[1, 0:10] == wf2.sourcegrid[1, 0:10]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[1, -10:] == wf2.sourcegrid[1, -10:]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[0, -10:] == nsrc.src_loc[0, -10:]): raise ValueError("Wave field and source not consistent.") # Loop over source locations print_each_n = max(5, round(max(ntraces // 5, 1), -1)) for i in range(ntraces): # noise source spectrum at this location S = nsrc.get_spect(i) if S.sum() == 0.: # If amplitude is 0, continue. (Spectrum has 0 phase anyway.) continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) Fs = conf['wavefield_sampling_rate'] s1 = db.get_seismograms(source=fsrc, receiver=rec1, dt=1. / Fs)[0].data * taper s2 = db.get_seismograms(source=fsrc, receiver=rec2, dt=1. / Fs)[0].data * taper s1 = np.ascontiguousarray(s1) s2 = np.ascontiguousarray(s2) else: if not wf1.fdomain: # read Green's functions s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) # Fourier transform for greater ease of convolution spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: pass # convolve G1G2 g1g2_tr = np.multiply(np.conjugate(spec1), spec2) # convolve noise source c = np.multiply(g1g2_tr, S) # transform back correlation += my_centered(np.fft.ifftshift(np.fft.irfft(c, n)), n_corr) * nsrc.surf_area[i] # occasional info if i % print_each_n == 0 and conf['verbose']: print("Finished {} of {} source locations.".format(i, ntraces)) # end of loop over all source locations ####################################### if not insta: wf1.file.close() wf2.file.close() # save output trace = Trace() trace.stats.sampling_rate = Fs trace.data = correlation # try to add some meta data try: sta1 = wf1.stats['reference_station'] sta2 = wf2.stats['reference_station'] trace.stats.station = sta1.split('.')[1] trace.stats.network = sta1.split('.')[0] trace.stats.location = sta1.split('.')[2] trace.stats.channel = sta1.split('.')[3] trace.stats.sac = {} trace.stats.sac['kuser0'] = sta2.split('.')[1] trace.stats.sac['kuser1'] = sta2.split('.')[0] trace.stats.sac['kuser2'] = sta2.split('.')[2] trace.stats.sac['kevnm'] = sta2.split('.')[3] except (KeyError, IndexError): pass trace.write(filename=corr_file, format='SAC')
def compute_kernel(input_files, all_conf, nsrc, all_ns, taper, insta=False): ntime, n, n_corr, Fs = all_ns wf1, wf2, adjt = input_files ######################################################################## # Prepare filenames and adjoint sources ######################################################################## adjt_srcs = [] for ix_f in range(all_conf.filtcnt): f = Stream() for a in adjt: adjtfile = a + '*.{}.sac'.format(ix_f) adjtfile = glob(adjtfile) try: f += read(adjtfile[0])[0] f[-1].data = my_centered(f[-1].data, n_corr) except IndexError: if all_conf.config['verbose']: print('No adjoint source found: {}\n'.format(a)) else: pass if len(f) > 0: adjt_srcs.append(f) else: return None # Uniform spatial weights. (current model is in the adjoint source) nsrc.distr_basis = np.ones(nsrc.distr_basis.shape) ntraces = nsrc.src_loc[0].shape[0] if insta: # open database dbpath = all_conf.config['wavefield_path'] # open and determine Fs, nt db = instaseis.open_db(dbpath) # get receiver locations lat1 = geograph_to_geocent(float(wf1[2])) lon1 = float(wf1[3]) rec1 = instaseis.Receiver(latitude=lat1, longitude=lon1) lat2 = geograph_to_geocent(float(wf2[2])) lon2 = float(wf2[3]) rec2 = instaseis.Receiver(latitude=lat2, longitude=lon2) else: wf1 = WaveField(wf1) wf2 = WaveField(wf2) # Make sure all is consistent if False in (wf1.sourcegrid[1, 0:10] == wf2.sourcegrid[1, 0:10]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[1, -10:] == wf2.sourcegrid[1, -10:]): raise ValueError("Wave fields not consistent.") if False in (wf1.sourcegrid[0, -10:] == nsrc.src_loc[0, -10:]): raise ValueError("Wave field and source not consistent.") kern = np.zeros( (nsrc.spect_basis.shape[0], all_conf.filtcnt, ntraces, len(adjt))) # Loop over locations print_each_n = max(5, round(max(ntraces // 5, 1), -1)) for i in range(ntraces): # noise source spectrum at this location # For the kernel, this contains only the basis functions of the # spectrum without weights; might still be location-dependent, # for example when constraining sensivity to ocean S = nsrc.get_spect(i) if S.sum() == 0.: # The spectrum has 0 phase so only checking # absolute value here continue if insta: # get source locations lat_src = geograph_to_geocent(nsrc.src_loc[1, i]) lon_src = nsrc.src_loc[0, i] fsrc = instaseis.ForceSource(latitude=lat_src, longitude=lon_src, f_r=1.e12) dt = 1. / all_conf.source_config['sampling_rate'] s1 = db.get_seismograms(source=fsrc, receiver=rec1, dt=dt)[0].data * taper s1 = np.ascontiguousarray(s1) s2 = db.get_seismograms(source=fsrc, receiver=rec2, dt=dt)[0].data * taper s2 = np.ascontiguousarray(s2) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: if not wf1.fdomain: s1 = np.ascontiguousarray(wf1.data[i, :] * taper) s2 = np.ascontiguousarray(wf2.data[i, :] * taper) spec1 = np.fft.rfft(s1, n) spec2 = np.fft.rfft(s2, n) else: spec1 = wf1.data[i, :] spec2 = wf2.data[i, :] g1g2_tr = np.multiply(np.conjugate(spec1), spec2) # spectrum for ix_spec in range(nsrc.spect_basis.shape[0]): c = np.multiply(g1g2_tr, nsrc.spect_basis[ix_spec, :]) ################################################################### # Get Kernel at that location ################################################################### corr_temp = my_centered(np.fft.fftshift(np.fft.irfft(c, n)), n_corr) ################################################################### # Apply the 'adjoint source' ################################################################### for ix_f in range(all_conf.filtcnt): f = adjt_srcs[ix_f] if f is None: continue for j in range(len(f)): delta = f[j].stats.delta kern[ix_spec, ix_f, i, j] = np.dot(corr_temp, f[j].data) * delta if i % print_each_n == 0 and all_conf.config['verbose']: print("Finished {} of {} source locations.".format(i, ntraces)) if not insta: wf1.file.close() wf2.file.close() return kern