Skip to Content
ExamplesPS2 Plotting scriptsPlot sensitivity kernel

Plot sensitivity kernels

Here, we demonstrate how to visualize the sensitivity kernel. First, we load necessary Python modules

import pygmt pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<") from pytomoatt.data import ATTData import numpy as np import os try: os.mkdir('img') except: pass

We choose to plot the kernel at 7-th iteration. Related file names are

# ---------------- read files ---------------- Nstep = "0007" kernel_list = {} # dictionary to store all the kernels # file names data_file = 'OUTPUT_FILES/out_data_sim_group_0.h5' # data file par_file = 'input_files/input_params.yaml' # parameter file grid_file = 'OUTPUT_FILES/out_data_grid.h5' # grid file group = 'model'

We will add all types of kernels to the dictionary kernel_list in the following subsections.

1. Original misfit kernel without modifications

We extract the misfit kernel without any modification, that is, the Frechet derivatives of the objective function with respect to unknown parameters.

  • The misfit kernel with respect to slowness: kernel_list['Ks_inv_0007'];
  • The misfit kernel with respect to xi: kernel_list['Kxi_inv_0007'];
  • The misfit kernel with respect to eta: kernel_list['Keta_inv_0007'].
# (Option 1) read original sensitivity kernel # Ks: kernel w.r.t. slowness at the 7-th iteration dataset = 'Ks_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Kxi: kernel w.r.t. xi (anisotropic parameter) at the 7-th iteration dataset = 'Kxi_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Keta: kernel w.r.t. eta (anisotropic parameter) at the 7-th iteration dataset = 'Keta_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray()

2. Kernel density

We extract the misfit kernel density, which is obtained by setting all adjoint source to 1.0. The kernel density reflects the distribution of sensitivity. It can be used to normalize the original kernel for higher convergent rates (see Section 3.3 in Chen et al., 2025  for details).

  • The kernel density with respect to slowness: kernel_list['Ks_density_inv_0007'];
  • The kernel density with respect to xi: kernel_list['Kxi_density_inv_0007'];
  • The kernel density with respect to eta: kernel_list['Keta_density_inv_0007'].
# (Option 2) read kernel_density # Ks_den: kernel density w.r.t. slowness at the 7-th iteration dataset = 'Ks_density_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Kxi_den: kernel density w.r.t. xi (anisotropic parameter) at the 7-th iteration dataset = 'Kxi_density_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Keta_den: kernel density w.r.t. eta (anisotropic parameter) at the 7-th iteration dataset = 'Keta_density_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray()

3. Smoothed kernel

We extract the smoothed kernels, which are obtained by applying multiple-grid parameterization and kernel density normalization to the original misfit kernel (see Section 3.3 in Chen et al., 2025  for details).

When using the gradient descent method, the model update at this step equals step_length * smoothed_kernel / max(abs(smoothed_kernel))

# (Option 3) read normalized kernel smoothed by multigrid parameterization # Ks_update: smoothed normalized kernel w.r.t. slowness at the 7-th iteration dataset = 'Ks_update_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Kxi_update: smoothed normalized kernel w.r.t. xi (anisotropic parameter) at the 7-th iteration dataset = 'Kxi_update_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray() # Keta_update: smoothed normalized kernel w.r.t. eta (anisotropic parameter) at the 7-th iteration dataset = 'Keta_update_inv_%s'%(Nstep) data = ATTData.read(data_file, par_file, grid_file, group, dataset) kernel_list[dataset] = data.to_xarray()

4. Plot horizontal profiles of kernels

Users can easily check the 3D kernel array and the coordinates in three directions

# ---------------- access 3D array ---------------- # we can access 3D dataset: dep_1d_array = kernel_list['Ks_inv_0007']["dep"] lat_1d_array = kernel_list['Ks_inv_0007']["lat"] lon_1d_array = kernel_list['Ks_inv_0007']["lon"] print("3D array of coordinates. \n dep: ", dep_1d_array.shape, " \n lat: ", lat_1d_array.shape, " \n lon: ", lon_1d_array.shape) array = kernel_list['Ks_inv_0007']["Ks_inv_0007"] print("3D array of kernel. \n Ks: ", array.shape)

The horizontal and vertical profiles of all kernels are plot via

# %% # ---------------- 2D depth profile of kernels ---------------- for dataset in kernel_list: # interp vel at depth = 20 km depth = 20.0 kernel = kernel_list[dataset].interp_dep(depth, field=dataset) # kernel[i,:] are (lon, lat, kernel) print("kernel at depth = ", depth, " km. kernel:", kernel.shape, ", (lon, lat, kernel)") # plot fig = pygmt.Figure() fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","+t%s"%(dataset)], projection="M10c") # base map pygmt.makecpt(cmap="jet", series=[-0.5, 0.5], background=True, reverse=True) # colorbar x = kernel[:,0]; # longitude y = kernel[:,1]; # latitude value = kernel[:,2]/np.nanmax(np.abs(kernel[:,2])) # traveltime grid = pygmt.surface(x=x, y=y, z=value, spacing=0.04,region=[0,2,0,2]) fig.grdimage(grid = grid) # plot figure fig.text(text="%d km"%(depth), x = 0.2 , y = 0.1, font = "14p,Helvetica-Bold,black", fill = "white") # colorbar fig.shift_origin(xshift=0, yshift=-1.5) fig.colorbar(frame = ["a0.5","y+l%s"%(dataset)], position="+e+w4c/0.3c+h") fig.savefig("img/3_dep_%s.png"%(dataset))
imgimgimg
imgimgimg
imgimgimg

4. Plot vertical profiles of kernels

# %% # ---------------- 2D vertical profile of kernels ---------------- for dataset in kernel_list: # interp from [0,0.6] in lon-lat to [2,0.6] in lon-lat, gap = 1 km start = [0,0.6]; end = [2,0.6]; gap = 1 kernel_sec = kernel_list[dataset].interp_sec(start, end, field=dataset, val = gap) # kernel_sec[i,:] are (lon, lat, dis, dep, kernel) print("kernel_sec:", kernel_sec.shape, ", (lon, lat, distance, depth, kernel)") # plot fig = pygmt.Figure() fig.basemap(region=[0,2,0,40], frame=["xa1+lLongitude","ya20+lDepth (km)","+t%s"%(dataset)], projection="X10c/-2c") # base map pygmt.makecpt(cmap="jet", series=[-0.5, 0.5], background=True, reverse=True) # colorbar x = kernel_sec[:,0]; # longitude y = kernel_sec[:,3]; # depth value = kernel_sec[:,4]/np.nanmax(np.abs(kernel_sec[:,4])) # traveltime grid = pygmt.surface(x=x, y=y, z=value, spacing="0.04/1",region=[0,2,0,40]) fig.grdimage(grid = grid) # plot figure fig.text(text="A", x = 0.1 , y = 5, font = "14p,Helvetica-Bold,black", fill = "white") fig.text(text="A@+'@+", x = 1.9 , y = 5, font = "14p,Helvetica-Bold,black", fill = "white") # colorbar fig.shift_origin(xshift=0, yshift=-2) fig.colorbar(frame = ["a0.5","y+l%s"%(dataset)], position="+e+w4c/0.3c+h") fig.savefig("img/3_sec_%s.png"%(dataset))
imgimgimg
imgimgimg
imgimgimg
Last updated on