Body Waves Synthetics Cross-correlation Functions¶
## Distributed python packages
import os
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import xarray as xr
import datetime
import pandas as pd
import time as ttime
from cartopy import crs as ccrs
from cartopy import feature as cfeature
from math import radians, log
from wmsan.synthetics import *
%matplotlib inline
__author__ = "Lisa Tomasetto"
__copyright__ = "Copyright 2024, UGA"
__credits__ = ["Lisa Tomasetto"]
__version__ = "0.1"
__maintainer__ = "Lisa Tomasetto"
__email__ = "lisa.tomasetto@univ-grenoble-alpes.fr"
__status__ = "Developpement"
Make Nice Plots¶
plt.style.use("ggplot")
SMALL_SIZE = 18
MEDIUM_SIZE = 22
BIGGER_SIZE = 24
plt.rc('font', size=SMALL_SIZE) # controls default text sizes
plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc('xtick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('ytick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('legend', fontsize=SMALL_SIZE) # legend fontsize
plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
matplotlib.rcParams['pdf.fonttype'] = 42
Theory¶
We will compute synthetic Cross-correlations between vertical components, using the formulation given in Tomasetto et al.(2024). Using the representation theorem and assuming spatially uncorrelated sources one can write the cross-correlation function between sensors A and B as:
$$C(r_A, r_B, t) = \mathcal{FT}^{-1}\left[ \int_{\partial D} G(r_A, r, f) G^*(r_B, r, f) S(r,f) dr \right]$$
with:
- $G(r_A, r, f)$ the Green's function between a source in $r$ and station A in $r_A$. Here computed in AxiSEM.
- $S(r,f)$ the source PSD at position $r$. Here given by the square of equivalent vertical force amplitude computed in microseismic_sources.ipynb.
- $^*$ denotes the complex conjugate.
- $\partial D$ the domain of potential sources, here, the ocean's surface.
- $\mathcal{FT}^{-1}$ the Fourier transform.
References¶
Create Synthetic Waveforms Database¶
In the following, we will use an AxiSEM archive file of seismic waveforms computed in ak135f model and sampled at 1 Hz.
First we will read and plot the archive.
[WARNING] Please download the archive before running the following cells!
Avalaible from: https://zenodo.org/records/11126562
Save in /ww3-source-maps/data/
## Open Archive
path_file_axisem = '../../data/NOISE_vertforce_dirac_0-ak135f_1.s_3600s.h5'
fe, time, N = get_synthetic_info(path_file_axisem=path_file_axisem)
distance = np.arange(0, 180.1, 0.1)
M = len(distance)
archive = np.zeros((M, N))
for i in range(M):
archive[i,:] = open_axisem(distance[i], path_file_axisem=path_file_axisem)
## Plot archive
plt.figure()
plt.pcolormesh(time, distance, archive,cmap='seismic', vmin= -10, vmax = 10)
plt.colorbar()
plt.xlabel('time')
plt.ylabel('distance')
plt.xlim(0, 3600)
plt.show()
Tapering¶
Then we taper the synthetics waveforms between two given body waves phases.
## Taper
file_name_taper = '../../data/NOISE_vertforce_dirac_0-ak135f_1.s_3600_tapered_P_PP.h5'
if os.path.isfile(file_name_taper):
print('Tapered archive already exists')
## Open tapered archive
h5_file = h5py.File(file_name_taper, 'r')
tapered_archive = h5_file['WAVEFORMS'][:]
else:
tapered_archive = taper_axisem_archive_body_waves(time, distance, archive_name=path_file_axisem, phase1='P', phase2='PP')
Tapered archive already exists
## Plot Tapered archive
plt.figure(figsize=(10, 5))
plt.pcolormesh(time, distance, tapered_archive, cmap='seismic', vmin=-10, vmax = 10)
plt.colorbar()
plt.xlabel('time')
plt.ylabel('distance')
plt.xlim(0, 3600)
plt.savefig('GF_archive.png', dpi=300, bbox_inches='tight')
file_name_spectrum = '../../data/spectrum_archive_tapered_P_PP.h5'
if os.path.isfile(file_name_spectrum):
print('Spectrum archive already exists')
## Open Spectrum archive
h5_file = h5py.File(file_name_spectrum, 'r')
spectrum_archive = h5_file['SPECTRUM'][:]
frequency = h5_file['frequency'][:]
distance = h5_file['distance'][:]
print(spectrum_archive.shape)
else:
## Create Spectrum archive from the tapered one
create_spectrum_archive(time, distance, tapered_archive, h5_name_spectrum = file_name_spectrum)
100%|██████████| 1801/1801 [00:00<00:00, 5610.40it/s]
## Spatial Exent
lon_min = -30
lon_max = 30
lat_min = 40
lat_max = 80
extent = [lon_min, lon_max, lat_min, lat_max]
Station Pairs and Metadata¶
## Station Pairs Metadata
df = pd.read_csv('../../data/stations_pair_bodywaves.txt', sep=',', header=None, index_col=False, names=['idA', 'idB', 'latA', 'latB', 'lonA', 'lonB'], dtype={'idA':str, 'idB':str, 'latA':float, 'latB':float, 'lonA':float, 'lonB':float}, engine='python')
# ## Plot
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection=ccrs.Mollweide())
#ax.set_extent(extent, crs=ccrs.PlateCarree())
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.BORDERS, linestyle='-', alpha=1)
ax.add_feature(cfeature.LAKES, alpha=0.5)
ax.add_feature(cfeature.RIVERS)
ax.add_feature(cfeature.STATES)
ax.add_feature(cfeature.LAND, color='linen', zorder=0)
ax.add_feature(cfeature.OCEAN, color='lightsteelblue', zorder=0)
for i in range(len(df)):
ax.annotate(df.idA[i], (df.lonA[i]-0.1, df.latA[i]+0.8), transform = ccrs.PlateCarree(), family = 'sans-serif')
ax.annotate(df.idB[i], (df.lonB[i]+0.1, df.latB[i]-0.8), transform = ccrs.PlateCarree(), family = 'sans-serif')
ax.plot((df.lonA[i], df.lonB[i]),(df.latA[i], df.latB[i]), transform = ccrs.PlateCarree(), color='k', alpha=0.5, linewidth=3)
df.plot.scatter(x='lonA', y='latA', s=30, ax=ax, c='r', transform = ccrs.PlateCarree())
df.plot.scatter(x='lonB', y='latB', s=30, ax=ax, c='r', transform = ccrs.PlateCarree())
plt.show()
Dates¶
## Dates
start = datetime(2014, 12, 8, 0, 0, 0)
end = datetime(2014, 12, 11, 23, 59, 59)
dates = pd.date_range(start, end, freq='3h')
dates_vector = create_date_vect(dates)
Open WAVEWATCHIII Equivalent Force Amplitude¶
## Open Model
path_model = './F/'
Open Synthetics Archive¶
## Open GF archive info
fe , freq, distance, spectrum_synth = open_archive('../../data/spectrum_archive_tapered_P_PP.h5')
N_time = len(time)
Synthetic Cross-correlation Computation¶
## Compute CCF and save it
### Station Pair Info
id_A = df.idA[0]
id_B = df.idB[0]
coords_staA = (df.lonA[0], df.latA[0])
coords_staB = (df.lonB[0], df.latB[0])
#### Keep Correlations
corr_3h = np.zeros((len(dates_vector), N_time))
### Date Info
for i, date_vect in enumerate(dates_vector):
### CCF
filename_ccf = './CCF/ccf_%s_%s_%d%02d%02d%02d.nc'%(id_A, id_B, date_vect[0],date_vect[1],date_vect[2],date_vect[3]) # File Name Understandable
if os.path.exists(filename_ccf): # Check if file already exists
print('%s already computed'%filename_ccf)
corr = xr.open_dataarray(filename_ccf)
else: # if not, compute CCF
t1 = ttime.perf_counter()
corr, time_corr = ccf_computation(coords_staA, coords_staB, path_model, date_vect, spectrum_synth,extent=extent, fe=fe, N=N_time, comp='Z')
t2 = ttime.perf_counter()
print(" Time for station pair: ", id_A, id_B, " elapsed: ", t2-t1)
try:
corr.to_netcdf('./CCF/ccf_%s_%s_%d%02d%02d%02d.nc'%(id_A, id_B, date_vect[0],date_vect[1],date_vect[2],date_vect[3]))
except:
print("make directory")
os.mkdir('./CCF')
corr.to_netcdf('./CCF/ccf_%s_%s_%d%02d%02d%02d.nc'%(id_A, id_B, date_vect[0],date_vect[1],date_vect[2],date_vect[3]))
corr_3h[i, :] = corr.values
# TAKES 12 MIN #
Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 24.22464458300965 make directory Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.536314760000096 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.434355288001825 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.597516499008634 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.44256342299923 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.427730536001036 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.496248310999363 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.782649754997692 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.361989252007334 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.757562218001112 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.480070133999106 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.45140269899275 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.41406988899689 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.715611527994042 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.53063509298954 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.480488692992367 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.523073303993442 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.50377771499916 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.248423570999876 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.323401860005106 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.484096909000073 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.37497093300044 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.35230963799404 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.393166608002502 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.505856843010406 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 24.32168182299938 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.442535009002313 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.597787550010253 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.694586485013133 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 24.342561407000176 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.758557949011447 Time for station pair: KZ.KUR01.00 MY.KOM.00 elapsed: 23.90396889600379
Plot¶
## Plot stack
plt.figure()
plt.plot(corr.time, np.mean(corr_3h, axis=0), 'k')
plt.xlim(400, 600)
plt.xlabel('Lag Time (s)')
plt.title('%s - %s stack'%(id_A, id_B))
plt.show()
## Plot CCF
normalize_corr = np.nanmax(abs(corr_3h))
dates_corr = dates
fig, ax = plt.subplots(figsize=(10,8))
im = plt.pcolormesh(corr.time, np.arange(len(dates_vector)), corr_3h/normalize_corr, cmap='seismic', vmin= -0.8, vmax = 0.8)
#ax.plot(corr.time, corr_3h.T/normalize_corr + np.arange(len(dates_vector)), 'k')
plt.colorbar(im)
ax.set_xlabel('Lag Time (s)')
ax.set_ylabel('Date')
ax.set_title('%s-%s CCF'%(id_A, id_B))
ax.set_xlim(400, 600)
ax.set_ylim(0, len(dates_vector))
ax.set_yticks(np.arange(len(dates_vector))[::8])
ax.set_yticklabels(dates[::8].strftime('%Y-%m-%dT%H'))
plt.savefig('ccf_%s_%s_synth.png'%(id_A, id_B), dpi=300, bbox_inches='tight')