initial upload

This commit is contained in:
2025-12-17 10:53:43 +08:00
commit f3f1778f77
308 changed files with 129940 additions and 0 deletions

BIN
examples/.DS_Store vendored Normal file

Binary file not shown.

7
examples/clean_examples.sh Executable file
View File

@@ -0,0 +1,7 @@
rm -r ./*/OUTPUT_FILES
rm ./*/*.dat
rm ./*/*.h5
rm ./*/*.txt
rm ./*/params_log.yaml
rm -r ./*/OUTPUT_FILES*
rm ./*/*/*.h5

View File

@@ -0,0 +1,215 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_noisy.dat # source receiver file path
swap_src_rec: true # swap source and receiver (only valid for regional source and receiver, those of tele remain unchanged)
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N61_61_61.h5 # path to initial model file
# model_1d_name: dummy_model_1d_name # 1D model name used in teleseismic 2D solver (iasp91, ak135, user_defined is available), defined in include/1d_model.h
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
nproc_sub: 1 # number of processors for sweep parallelization (parallel the fast sweep method)
use_gpu: false # true if use gpu (EXPERIMENTAL)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_inv # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false # True: output sensitivity kernel and kernel density. Default: false. File: 'out_data_sim_group_X'.
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do).
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 1
have_tele_data: false # An error will be reported if false but source out of study region is used. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 40 # maximum number of inversion iterations
optim_method: 0 # optimization method. 0 : grad_descent, 1 : halve-stepping, 2 : lbfgs (EXPERIMENTAL)
#common parameters for all optim methods
step_length: 0.02 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
step_method: 1 # the method to modulate step size. 0: according to objective function; 1: according to gradient direction
# if step_method:0. if objective function increase, step size -> step length * step_length_decay.
step_length_decay: 0.9 # default: 0.9
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.2] # default: [0.5,1.2]
# Kdensity_coe is used to rescale the final kernel: kernel -> kernel / pow(density of kernel, Kdensity_coe). if Kdensity_coe > 0, the region with less data will be enhanced during the inversion
# e.g., if Kdensity_coe = 0, kernel remains upchanged; if Kdensity_coe = 1, kernel is fully normalized. 0.5 or less is recommended if really required.
Kdensity_coe: 0 # default: 0.0, limited range: 0.0 - 0.95
# smoothing
smoothing:
smooth_method: 0 # 0: multiparametrization, 1: laplacian smoothing (EXPERIMENTAL)
l_smooth_rtp: [1, 1, 1] # smoothing coefficients for laplacian smoothing
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: true # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: true # true if use uniform inversion grid for lon, false if use flexible inversion grid
# -------------- uniform inversion grid setting --------------
# settings for uniform inversion grid
n_inv_dep_lat_lon: [12, 9, 9] # number of the base inversion grid points
min_max_dep_inv: [-10, 50] # depth in km (Radius of the earth is defined in config.h/R_earth)
min_max_lat_inv: [0, 2] # latitude in degree
min_max_lon_inv: [0, 2] # longitude in degree
# -------------- flexible inversion grid setting --------------
# settings for flexible inversion grid
dep_inv: [-10, 0, 10, 20, 30, 40, 50, 60] # inversion grid for vel in depth (km)
lat_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in latitude (degree)
lon_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# In the following data subsection, XXX_weight means a weight is assigned to the data, influencing the objective function and gradient
# XXX_weight : [d1,d2,w1,w2] means:
# if XXX < d1, weight = w1
# if d1 <= XXX < d2, weight = w1 + (XXX-d1)/(d2-d1)*(w2-w1), (linear interpolation)
# if d2 <= XXX , weight = w2
# You can easily set w1 = w2 = 1.0 to normalize the weight related to XXX.
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: true # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight: [100, 200, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: false # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: false # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_weight: 1 # weight of absolute traveltime data after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data after balance, default: 1.0
teleseismic_weight: 1 # weight of teleseismic data after balance, default: 1.0 (exclude in this version)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : true # update azimuthal anisotropy (xi, eta) or not. default: false

View File

@@ -0,0 +1,50 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_config.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_61_61.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_signal # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
run_mode: 0

View File

@@ -0,0 +1,29 @@
# seismic tomography
This is a toy model to invert traveltimes for Vp and anisotropy (Figure 8c.)
Reference:
[1] J. Chen, M. Nagaso, M. Xu, and P. Tong, TomoATT: An open-source package for Eikonal equation-based adjoint-state traveltime tomography for seismic velocity and azimuthal anisotropy, submitted.
https://doi.org/10.48550/arXiv.2412.00031
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.
2. After inversion, run `plot_output.py` to plot the results.
The initial and true models:
![](img/model_setting.jpg)
The inversion result:
![](img/model_inv.jpg)

View File

@@ -0,0 +1,16 @@
from pytomoatt.src_rec import SrcRec
def assign_noise_to_src_rec_file(in_fname, out_fname, noise_level=0.1):
sr = SrcRec.read(in_fname)
sr.add_noise(noise_level)
sr.write(out_fname)
if __name__ == "__main__":
in_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward.dat" # input source receiver file
out_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_noisy.dat" # output source receiver file
sigma = 0.1 # noise level in seconds
assign_noise_to_src_rec_file(in_fname, out_fname, noise_level=sigma)

View File

@@ -0,0 +1,250 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
import os
# %%
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# read models
Ngrid = [61,61,61]
data_file = '2_models/model_init_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
par_file = '3_input_params/input_params_signal.yaml'
model = ATTModel.read(data_file, par_file)
initial_model = model.to_xarray()
data_file = '2_models/model_ckb_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
model = ATTModel.read(data_file, par_file)
ckb_model = model.to_xarray()
# initial model
depth = 10.0
vel_init = initial_model.interp_dep(depth, field='vel')
start = [1.25,0]; end = [1.25,2]
vel_init_sec = initial_model.interp_sec(start, end, field='vel', val = 1)
# checkerboard model
vel_ckb = ckb_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
vel_ckb_sec = ckb_model.interp_sec(start, end, field='vel', val = 1)
# anisotropic arrow
samp_interval = 3
length = 7
width = 0.1
ani_thd = 0.02
ani_ckb_phi = ckb_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_ckb_epsilon = ckb_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_ckb = np.hstack([ani_ckb_phi, ani_ckb_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_ckb_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_ckb_epsilon[:,2] > ani_thd)
ani_ckb = ani_ckb[idx[0],:]
try:
os.mkdir('img')
except:
pass
# %%
# read src_rec_file for data
from pytomoatt.src_rec import SrcRec
sr = SrcRec.read('1_src_rec_files/src_rec_config.dat')
station = sr.receivers[['stlo','stla','stel']].values.T
true_loc = sr.sources[['evlo','evla','evdp']].values.T
earthquake = true_loc
# %%
# categorize earthquakes
ev_idx1 = []
ev_idx2 = []
ev_idx3 = []
for i in range(earthquake.shape[1]):
dep = earthquake[2,i]
if dep < 15:
ev_idx1.append(i)
elif dep < 25:
ev_idx2.append(i)
elif dep < 35:
ev_idx3.append(i)
# %%
# plot the checkerboard model
fig = pygmt.Figure()
region = [0,2,0,2]
frame = ["xa1","ya1","nSWe"]
projection = "M10c"
spacing = 0.04
vel_range = 20
# -------------- initial model and earthquake location --------------
fig.basemap(region=region, frame=["xa1","ya1","+tInitial model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_init[:,0]; y = vel_init[:,1]; value = (vel_init[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = true_loc[0,ev_idx1], y = true_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = true_loc[0,ev_idx2], y = true_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = true_loc[0,ev_idx3], y = true_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
fig.plot(x = station[0,:], y = station[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# # anisotropic arrow
# fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_init_sec[:,3]; y = vel_init_sec[:,1]; value = (vel_init_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = true_loc[2,ev_idx1], y = true_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = true_loc[2,ev_idx2], y = true_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = true_loc[2,ev_idx3], y = true_loc[1,ev_idx3], style = "c0.1c", fill = "black")
fig.shift_origin(xshift=4)
# -------------- checkerboard model --------------
fig.basemap(region=region, frame=["xa1","ya1","+tTrue model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_ckb[:,0]; y = vel_ckb[:,1]; value = (vel_ckb[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = earthquake[0,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = earthquake[0,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = earthquake[0,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_ckb_sec[:,3]; y = vel_ckb_sec[:,1]; value = (vel_ckb_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = earthquake[2,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = earthquake[2,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = earthquake[2,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_setting.png', dpi=300)
# %%
# plot the inversion result
# read models
tag = "inv"
data_file = "OUTPUT_FILES/OUTPUT_FILES_%s/final_model.h5"%(tag)
model = ATTModel.read(data_file, par_file)
inv_model = model.to_xarray()
vel_inv = inv_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
vel_inv_sec = inv_model.interp_sec(start, end, field='vel', val = 1)
x_sec = vel_inv_sec[:,3]; y_sec = vel_inv_sec[:,1]; value_sec = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
ani_inv_phi = inv_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_inv_epsilon = inv_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_inv = np.hstack([ani_inv_phi, ani_inv_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_inv_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_inv_epsilon[:,2] > ani_thd)
ani_inv = ani_inv[idx[0],:]
# plot the inversion result
fig = pygmt.Figure()
region = [0,2,0,2]
frame = ["xa1","ya1","+tInversion results"]
projection = "M10c"
spacing = 0.04
vel_range = 20
# -------------- checkerboard model --------------
fig.basemap(region=region, frame=frame, projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# # earthquakes
# fig.plot(x = earthquake[0,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
# fig.plot(x = earthquake[0,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
# fig.plot(x = earthquake[0,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_inv, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_inv_sec[:,3]; y = vel_inv_sec[:,1]; value = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# # earthquakes
# fig.plot(x = earthquake[2,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
# fig.plot(x = earthquake[2,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
# fig.plot(x = earthquake[2,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_%s.png'%(tag), dpi=300)

View File

@@ -0,0 +1,63 @@
# download src_ref_files from Zenodo
import os
import numpy as np
import sys
try:
from pytomoatt.model import ATTModel
from pytomoatt.checkerboard import Checker
from pytomoatt.src_rec import SrcRec
except:
print("ERROR: ATTModel not found. Please install pytomoatt first."
"See https://tomoatt.github.io/PyTomoATT/installation.html for details.")
sys.exit(1)
class BuildInitialModel():
def __init__(self, par_file="./3_input_params/input_params_signal.yaml", output_dir="2_models"):
"""
Build initial model for tomography inversion
"""
self.am = ATTModel(par_file)
self.output_dir = output_dir
def build_initial_model(self, vel_min=5.0, vel_max=8.0):
"""
Build initial model for tomography inversion
"""
self.am.vel[self.am.depths < 0, :, :] = vel_min
idx = np.where((0 <= self.am.depths) & (self.am.depths < 40.0))[0]
self.am.vel[idx, :, :] = np.linspace(vel_min, vel_max, idx.size)[::-1][:, np.newaxis, np.newaxis]
self.am.vel[self.am.depths >= 40.0, :, :] = vel_max
def build_ckb_model(output_dir="2_models"):
cbk = Checker(f'{output_dir}/model_init_N61_61_61.h5', para_fname="./3_input_params/input_params_signal.yaml")
cbk.checkerboard(
n_pert_x=2, n_pert_y=2, n_pert_z=2,
pert_vel=0.2, pert_ani=0.1, ani_dir=60.0,
lim_x=[0.5, 1.5], lim_y=[0.5, 1.5], lim_z=[0, 40]
)
cbk.write(f'{output_dir}/model_ckb_N61_61_61.h5')
if __name__ == "__main__":
# download src_rec_config.dat
url = 'https://zenodo.org/records/14053821/files/src_rec_config.dat'
path = "1_src_rec_files/src_rec_config.dat"
os.makedirs(os.path.dirname(path), exist_ok=True)
if not os.path.exists(path):
sr = SrcRec.read(url)
sr.write(path)
# build initial model
output_dir = "2_models"
os.makedirs(output_dir, exist_ok=True)
bim = BuildInitialModel(output_dir=output_dir)
bim.build_initial_model()
bim.am.write('{}/model_init_N{:d}_{:d}_{:d}.h5'.format(bim.output_dir, *bim.am.n_rtp))
# build ckb model
build_ckb_model(output_dir)

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Step 1: Generate necessary input files
python prepare_input_files.py
# Step 2: Run forward modeling
# for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_signal.yaml
# Step 3: Assign data noise to the observational data
python assign_gaussian_noise.py
# Step 4: Do inversion
# for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_inv.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_inv.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_inv.yaml
# Step 5 (Optional): Plot the results
python plot_output.py

View File

@@ -0,0 +1,114 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_61_61.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_loc # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 2
#################################################
# relocation parameters setting #
#################################################
relocation: # update earthquake hypocenter and origin time (when run_mode : 2 and 3)
min_Ndata: 4 # if the number of data of the earthquake is less than <min_Ndata>, the earthquake will not be relocated. defaut value: 4
# relocation_strategy
step_length : 0.01 # initial step length of relocation perturbation. 0.01 means maximum 1% perturbation for each iteration.
step_length_decay : 0.9 # if objective function increase, step size -> step length * step_length_decay. default: 0.9
rescaling_dep_lat_lon_ortime: [10.0, 15.0, 15.0, 1.0] # The perturbation is related to <rescaling_dep_lat_lon_ortime>. Unit: km,km,km,second
max_change_dep_lat_lon_ortime: [10.0, 15.0, 15.0, 1.0] # the change of dep,lat,lon,ortime do not exceed max_change. Unit: km,km,km,second
max_iterations : 201 # maximum number of iterations for relocation
tol_gradient : 0.0001 # if the norm of gradient is smaller than the tolerance, the iteration of relocation terminates
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time : true # 'yes' for using absolute traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time : false # 'yes' for using common source differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time : false # 'yes' for using common receiver differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)

View File

@@ -0,0 +1,50 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_config.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_61_61.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_signal # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
run_mode: 0

View File

@@ -0,0 +1,29 @@
# earthquake location
This is a toy model to invert traveltimes for locating earthquakes (Figure 8a.)
Reference:
[1] J. Chen, M. Nagaso, M. Xu, and P. Tong, TomoATT: An open-source package for Eikonal equation-based adjoint-state traveltime tomography for seismic velocity and azimuthal anisotropy, submitted.
https://doi.org/10.48550/arXiv.2412.00031
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.
2. After inversion, run `plot_output.py` to plot the results.
The initial and true models:
![](img/model_setting.jpg)
The location results:
![](img/model_loc.jpg)

View File

@@ -0,0 +1,30 @@
from pytomoatt.src_rec import SrcRec
class AssignNoise:
def __init__(self, in_fname, out_fname):
self.in_fname = in_fname
self.out_fname = out_fname
self.sr = SrcRec.read(self.in_fname)
def assign_noise_for_tt(self, noise_level=0.1):
self.sr.add_noise(noise_level)
def assign_noise_for_src(self, lat_pert=0.1, lon_pert=0.1, dep_pert=10, tau_pert=0.5):
self.sr.add_noise_to_source(lat_pert, lon_pert, dep_pert, tau_pert)
if __name__ == "__main__":
in_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward.dat" # input source receiver file
out_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat" # output source receiver file
sigma = 0.1 # noise level in seconds
lat_pert = 0.1 # assign noise for latitude in degrees
lon_pert = 0.1 # assign noise for longitude in degrees
dep_pert = 10 # assign noise for depth in km
tau_pert = 0.5 # assign noise for origin time in seconds
# Initialize the instance
an = AssignNoise(in_fname, out_fname)
# Assign noise for travel time
an.assign_noise_for_tt(sigma)
# Assign noise for source
an.assign_noise_for_src(lat_pert, lon_pert, dep_pert, tau_pert)
# Write the output file
an.sr.write(out_fname)

View File

@@ -0,0 +1,254 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
import os
# %%
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# read models
Ngrid = [61,61,61]
data_file = '2_models/model_init_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
par_file = '3_input_params/input_params_signal.yaml'
model = ATTModel.read(data_file, par_file)
initial_model = model.to_xarray()
data_file = '2_models/model_ckb_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
model = ATTModel.read(data_file, par_file)
ckb_model = model.to_xarray()
# initial model
depth = 10.0
vel_init = initial_model.interp_dep(depth, field='vel')
start = [1.25,0]; end = [1.25,2]
vel_init_sec = initial_model.interp_sec(start, end, field='vel', val = 1)
# checkerboard model
vel_ckb = ckb_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
vel_ckb_sec = ckb_model.interp_sec(start, end, field='vel', val = 1)
# anisotropic arrow
samp_interval = 3
length = 7
width = 0.1
ani_thd = 0.02
ani_ckb_phi = ckb_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_ckb_epsilon = ckb_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_ckb = np.hstack([ani_ckb_phi, ani_ckb_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_ckb_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_ckb_epsilon[:,2] > ani_thd)
ani_ckb = ani_ckb[idx[0],:]
try:
os.mkdir('img')
except:
pass
# %%
# read src_rec_file for data
from pytomoatt.src_rec import SrcRec
sr = SrcRec.read('1_src_rec_files/src_rec_config.dat')
station = sr.receivers[['stlo','stla','stel']].values.T
true_loc = sr.sources[['evlo','evla','evdp']].values.T
earthquake = true_loc
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat')
init_loc = sr.sources[['evlo','evla','evdp']].values.T
# %%
# categorize earthquakes
ev_idx1 = []
ev_idx2 = []
ev_idx3 = []
for i in range(earthquake.shape[1]):
dep = earthquake[2,i]
if dep < 15:
ev_idx1.append(i)
elif dep < 25:
ev_idx2.append(i)
elif dep < 35:
ev_idx3.append(i)
# %%
# plot the model setting
fig = pygmt.Figure()
region = [0,2,0,2]
frame = ["xa1","ya1"]
projection = "M10c"
spacing = 0.04
vel_range = 20
# -------------- initial model and earthquake location --------------
fig.basemap(region=region, frame=["xa1","ya1","+tInitial model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_ckb[:,0]; y = vel_ckb[:,1]; value = (vel_ckb[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = init_loc[0,ev_idx1], y = init_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = init_loc[0,ev_idx2], y = init_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = init_loc[0,ev_idx3], y = init_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
fig.plot(x = station[0,:], y = station[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_ckb_sec[:,3]; y = vel_ckb_sec[:,1]; value = (vel_ckb_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = init_loc[2,ev_idx1], y = init_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = init_loc[2,ev_idx2], y = init_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = init_loc[2,ev_idx3], y = init_loc[1,ev_idx3], style = "c0.1c", fill = "black")
fig.shift_origin(xshift=4)
# -------------- true model and earthquake location --------------
fig.basemap(region=region, frame=["xa1","ya1","+tTrue model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_ckb[:,0]; y = vel_ckb[:,1]; value = (vel_ckb[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = earthquake[0,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = earthquake[0,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = earthquake[0,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_ckb_sec[:,3]; y = vel_ckb_sec[:,1]; value = (vel_ckb_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = earthquake[2,ev_idx1], y = earthquake[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = earthquake[2,ev_idx2], y = earthquake[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = earthquake[2,ev_idx3], y = earthquake[1,ev_idx3], style = "c0.1c", fill = "black")
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_setting.png', dpi=300)
# %%
# plot the location result
# read models
tag = "loc"
data_file = "OUTPUT_FILES/OUTPUT_FILES_%s/final_model.h5"%(tag)
model = ATTModel.read(data_file, par_file)
inv_model = model.to_xarray()
vel_inv = inv_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
vel_inv_sec = inv_model.interp_sec(start, end, field='vel', val = 1)
x_sec = vel_inv_sec[:,3]; y_sec = vel_inv_sec[:,1]; value_sec = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
ani_inv_phi = inv_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_inv_epsilon = inv_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_inv = np.hstack([ani_inv_phi, ani_inv_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_inv_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_inv_epsilon[:,2] > ani_thd)
ani_inv = ani_inv[idx[0],:]
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_loc/src_rec_file_reloc_0201.dat')
re_loc = sr.sources[['evlo','evla','evdp']].values.T
# plot the inversion result
fig = pygmt.Figure()
region = [0,2,0,2]
frame = ["xa1","ya1","+tLocation results"]
projection = "M10c"
spacing = 0.04
vel_range = 20
# -------------- checkerboard model --------------
fig.basemap(region=region, frame=frame, projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = re_loc[0,ev_idx1], y = re_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = re_loc[0,ev_idx2], y = re_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = re_loc[0,ev_idx3], y = re_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_inv, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_inv_sec[:,3]; y = vel_inv_sec[:,1]; value = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = re_loc[2,ev_idx1], y = re_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = re_loc[2,ev_idx2], y = re_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = re_loc[2,ev_idx3], y = re_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_%s.png'%(tag), dpi=300)

View File

@@ -0,0 +1,61 @@
import numpy as np
import os
import sys
try:
from pytomoatt.checkerboard import Checker
from pytomoatt.src_rec import SrcRec
from pytomoatt.model import ATTModel
except:
print("ERROR: ATTModel not found. Please install pytomoatt first."
"See https://tomoatt.github.io/PyTomoATT/installation.html for details.")
sys.exit(1)
class BuildInitialModel():
def __init__(self, par_file="./3_input_params/input_params_signal.yaml", output_dir="2_models"):
"""
Build initial model for tomography inversion
"""
self.am = ATTModel(par_file)
self.output_dir = output_dir
def build_initial_model(self, vel_min=5.0, vel_max=8.0):
"""
Build initial model for tomography inversion
"""
self.am.vel[self.am.depths < 0, :, :] = vel_min
idx = np.where((0 <= self.am.depths) & (self.am.depths < 40.0))[0]
self.am.vel[idx, :, :] = np.linspace(vel_min, vel_max, idx.size)[::-1][:, np.newaxis, np.newaxis]
self.am.vel[self.am.depths >= 40.0, :, :] = vel_max
def build_ckb_model(output_dir="2_models"):
cbk = Checker(f'{output_dir}/model_init_N61_61_61.h5', para_fname="./3_input_params/input_params_signal.yaml")
cbk.checkerboard(
n_pert_x=2, n_pert_y=2, n_pert_z=2,
pert_vel=0.2, pert_ani=0.1, ani_dir=60.0,
lim_x=[0.5, 1.5], lim_y=[0.5, 1.5], lim_z=[0, 40]
)
cbk.write(f'{output_dir}/model_ckb_N61_61_61.h5')
if __name__ == "__main__":
# download src_rec_file
url = 'https://zenodo.org/records/14053821/files/src_rec_config.dat'
path = "1_src_rec_files/src_rec_config.dat"
os.makedirs(os.path.dirname(path), exist_ok=True)
if not os.path.exists(path):
sr = SrcRec.read(url)
sr.write(path)
# build initial model
output_dir = "2_models"
os.makedirs(output_dir, exist_ok=True)
bim = BuildInitialModel(output_dir=output_dir)
bim.build_initial_model()
bim.am.write('{}/model_init_N{:d}_{:d}_{:d}.h5'.format(bim.output_dir, *bim.am.n_rtp))
build_ckb_model(output_dir)

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Step 1: Generate necessary input files
python prepare_input_files.py
# Step 2: Run forward modeling
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_signal.yaml
# Step 3: Assign data noise and location perturbation to the observational data
python assign_gaussian_noise.py
# Step 4: Do relocation
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_loc.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_loc.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_loc.yaml
# Step 5 (Optional): Plot the results
# python plot_output.py

View File

@@ -0,0 +1,114 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N61_61_61.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_joint_step1 # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 2
#################################################
# relocation parameters setting #
#################################################
relocation: # update earthquake hypocenter and origin time (when run_mode : 2 and 3)
min_Ndata: 4 # if the number of data of the earthquake is less than <min_Ndata>, the earthquake will not be relocated. defaut value: 4
# relocation_strategy
step_length : 0.01 # initial step length of relocation perturbation. 0.01 means maximum 1% perturbation for each iteration.
step_length_decay : 0.9 # if objective function increase, step size -> step length * step_length_decay. default: 0.9
rescaling_dep_lat_lon_ortime: [10.0, 15.0, 15.0, 1.0] # The perturbation is related to <rescaling_dep_lat_lon_ortime>. Unit: km,km,km,second
max_change_dep_lat_lon_ortime: [10.0, 15.0, 15.0, 1.0] # the change of dep,lat,lon,ortime do not exceed max_change. Unit: km,km,km,second
max_iterations : 50 # maximum number of iterations for relocation
tol_gradient : 0.0001 # if the norm of gradient is smaller than the tolerance, the iteration of relocation terminates
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time : true # 'yes' for using absolute traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time : false # 'yes' for using common source differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time : true # 'yes' for using common receiver differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)

View File

@@ -0,0 +1,312 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_joint_step1/src_rec_file_reloc_0050_obs.dat # source receiver file path
swap_src_rec: true # swap source and receiver (only valid for regional source and receiver, those of tele remain unchanged)
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N61_61_61.h5 # path to initial model file
# model_1d_name: dummy_model_1d_name # 1D model name used in teleseismic 2D solver (iasp91, ak135, user_defined is available), defined in include/1d_model.h
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
nproc_sub: 1 # number of processors for sweep parallelization (parallel the fast sweep method)
use_gpu: false # true if use gpu (EXPERIMENTAL)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_joint_step2 # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false # True: output sensitivity kernel and kernel density. Default: false. File: 'out_data_sim_group_X'.
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do).
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 3
have_tele_data: false # An error will be reported if false but source out of study region is used. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 40 # maximum number of inversion iterations
optim_method: 0 # optimization method. 0 : grad_descent, 1 : halve-stepping, 2 : lbfgs (EXPERIMENTAL)
#common parameters for all optim methods
step_length: 0.02 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
step_method: 1 # the method to modulate step size. 0: according to objective function; 1: according to gradient direction
# if step_method:0. if objective function increase, step size -> step length * step_length_decay.
step_length_decay: 0.9 # default: 0.9
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.2] # default: [0.5,1.2]
# Kdensity_coe is used to rescale the final kernel: kernel -> kernel / pow(density of kernel, Kdensity_coe). if Kdensity_coe > 0, the region with less data will be enhanced during the inversion
# e.g., if Kdensity_coe = 0, kernel remains upchanged; if Kdensity_coe = 1, kernel is fully normalized. 0.5 or less is recommended if really required.
Kdensity_coe: 0 # default: 0.0, limited range: 0.0 - 0.95
# parameters for optim_method 1 (halve-stepping) or 2 (lbfgs)
optim_method_1_2:
max_sub_iterations: 20 # maximum number of each sub-iteration
regularization_weight: 0.5 # weight value for regularization (lbfgs mode only)
coefs_regulalization_rtp: [1, 1, 1] # regularization coefficients for rtp (lbfgs mode only)
# smoothing
smoothing:
smooth_method: 0 # 0: multiparametrization, 1: laplacian smoothing (EXPERIMENTAL)
l_smooth_rtp: [1, 1, 1] # smoothing coefficients for laplacian smoothing
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: true # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: true # true if use uniform inversion grid for lon, false if use flexible inversion grid
# -------------- uniform inversion grid setting --------------
# settings for uniform inversion grid
n_inv_dep_lat_lon: [12, 9, 9] # number of the base inversion grid points
min_max_dep_inv: [-10, 50] # depth in km (Radius of the earth is defined in config.h/R_earth)
min_max_lat_inv: [0, 2] # latitude in degree
min_max_lon_inv: [0, 2] # longitude in degree
# -------------- flexible inversion grid setting --------------
# settings for flexible inversion grid
dep_inv: [-10, 0, 10, 20, 30, 40, 50, 60] # inversion grid for vel in depth (km)
lat_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in latitude (degree)
lon_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# if we want to use another inversion grid for inverting anisotropy, set invgrid_ani: true (default: false)
invgrid_ani: false
# ---------- uniform inversion grid setting for anisotropy ----------
n_inv_dep_lat_lon_ani: [12, 11, 11] # number of the base inversion grid points
min_max_dep_inv_ani: [-7, 63] # depth in km (Radius of the earth is defined in config.h/R_earth)
min_max_lat_inv_ani: [30, 32] # latitude in degree
min_max_lon_inv_ani: [30, 32] # longitude in degree
# ---------- flexible inversion grid setting for anisotropy ----------
# settings for flexible inversion grid for anisotropy
dep_inv_ani: [-7, -3, 0, 3, 7, 12, 18, 25, 33, 42, 52, 63] # inversion grid for ani in depth (km)
lat_inv_ani: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for ani in latitude (degree)
lon_inv_ani: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for ani in longitude (degree)
trapezoid_ani: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# inversion grid volume rescale (kernel -> kernel / volume of inversion grid mesh),
# this precondition may be carefully applied if the sizes of inversion grids are unbalanced
invgrid_volume_rescale: false
# path to station correction file (under development)
use_sta_correction: false
# initial_sta_correction_file: dummy_sta_correction_file # the path of initial station correction
step_length_sta_correction: 0.001 # step length relate to the update of station correction terms
# In the following data subsection, XXX_weight means a weight is assigned to the data, influencing the objective function and gradient
# XXX_weight : [d1,d2,w1,w2] means:
# if XXX < d1, weight = w1
# if d1 <= XXX < d2, weight = w1 + (XXX-d1)/(d2-d1)*(w2-w1), (linear interpolation)
# if d2 <= XXX , weight = w2
# You can easily set w1 = w2 = 1.0 to normalize the weight related to XXX.
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: true # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight: [100, 200, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: true # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: true # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_weight: 1 # weight of absolute traveltime data after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data after balance, default: 1.0
teleseismic_weight: 1 # weight of teleseismic data after balance, default: 1.0 (exclude in this version)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : true # update azimuthal anisotropy (xi, eta) or not. default: false
# -------------- for teleseismic inversion (under development) --------------
# depth_taper : [d1,d2] means:
# if XXX < d1, kernel <- kernel * 0.0
# if d1 <= XXX < d2, kernel <- kernel * (XXX-d1)/(d2-d1), (linear interpolation)
# if d2 <= XXX , kernel <- kernel * 1.0
# You can easily set d1 = -200, d1 = -100 to remove this taper.
depth_taper : [-1e+07, -1e+07]
#################################################
# relocation parameters setting #
#################################################
relocation: # update earthquake hypocenter and origin time (when run_mode : 2 and 3)
min_Ndata: 4 # if the number of data of the earthquake is less than <min_Ndata>, the earthquake will not be relocated. defaut value: 4
# relocation_strategy
step_length : 0.01 # initial step length of relocation perturbation. 0.01 means maximum 1% perturbation for each iteration.
step_length_decay : 0.9 # if objective function increase, step size -> step length * step_length_decay. default: 0.9
rescaling_dep_lat_lon_ortime : [10, 15, 15, 1] # The perturbation is related to <rescaling_dep_lat_lon_ortime>. Unit: km,km,km,second
max_change_dep_lat_lon_ortime : [10, 15, 15, 1] # the change of dep,lat,lon,ortime do not exceed max_change. Unit: km,km,km,second
max_iterations : 201 # maximum number of iterations for relocation
tol_gradient : 0.0001 # if the norm of gradient is smaller than the tolerance, the iteration of relocation terminates
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time : true # 'yes' for using absolute traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight : [1, 3, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time : false # 'yes' for using common source differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight : [100, 200, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time : true # 'yes' for using common receiver differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [15, 30, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight : [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: true # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_local_weight: 1 # weight of absolute traveltime data for relocation after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data for relocation after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data for relocation after balance, default: 1.0
####################################################################
# inversion strategy for tomography and relocation #
####################################################################
inversion_strategy: # update model parameters and earthquake hypocenter iteratively (when run_mode : 3)
inv_mode : 1 # 0 for update model parameters and relocation iteratively. 1 for update model parameters and relocation simultaneously.
# for inv_mode : 0, parameters below are required
inv_mode_0: # update model for <model_update_N_iter> steps, then update location for <relocation_N_iter> steps, and repeat the process for <max_loop> loops.
model_update_N_iter : 1
relocation_N_iter : 1
max_loop : 10
# for inv_mode : 1, parameters below are required
inv_mode_1: # update model and location simultaneously for <max_loop> loops.
max_loop : 40

View File

@@ -0,0 +1,139 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_joint_step2/src_rec_file_inv_0039_reloc_0039_obs.dat # source receiver file path
swap_src_rec: true # swap source and receiver (only valid for regional source and receiver, those of tele remain unchanged)
#################################################
# initial model file path #
#################################################
model:
init_model_path: OUTPUT_FILES/OUTPUT_FILES_joint_step2/final_model.h5 # path to initial model file
# model_1d_name: dummy_model_1d_name # 1D model name used in teleseismic 2D solver (iasp91, ak135, user_defined is available), defined in include/1d_model.h
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
nproc_sub: 1 # number of processors for sweep parallelization (parallel the fast sweep method)
use_gpu: false # true if use gpu (EXPERIMENTAL)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_joint_step3 # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false # True: output sensitivity kernel and kernel density. Default: false. File: 'out_data_sim_group_X'.
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do).
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 2
have_tele_data: false # An error will be reported if false but source out of study region is used. Default: false.
#################################################
# relocation parameters setting #
#################################################
relocation: # update earthquake hypocenter and origin time (when run_mode : 2 and 3)
min_Ndata: 4 # if the number of data of the earthquake is less than <min_Ndata>, the earthquake will not be relocated. defaut value: 4
# relocation_strategy
step_length : 0.01 # initial step length of relocation perturbation. 0.01 means maximum 1% perturbation for each iteration.
step_length_decay : 0.9 # if objective function increase, step size -> step length * step_length_decay. default: 0.9
rescaling_dep_lat_lon_ortime : [10, 15, 15, 1] # The perturbation is related to <rescaling_dep_lat_lon_ortime>. Unit: km,km,km,second
max_change_dep_lat_lon_ortime : [10, 15, 15, 1] # the change of dep,lat,lon,ortime do not exceed max_change. Unit: km,km,km,second
max_iterations : 100 # maximum number of iterations for relocation
tol_gradient : 0.0001 # if the norm of gradient is smaller than the tolerance, the iteration of relocation terminates
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time : false # 'yes' for using absolute traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight : [1, 3, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time : false # 'yes' for using common source differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight : [100, 200, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time : true # 'yes' for using common receiver differential traveltime data to update ortime and location; 'no' for not using (no need to set parameters in this section)
residual_weight : [15, 30, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight : [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: true # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_local_weight: 1 # weight of absolute traveltime data for relocation after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data for relocation after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data for relocation after balance, default: 1.0

View File

@@ -0,0 +1,50 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_config.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_61_61.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_signal # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
run_mode: 0

View File

@@ -0,0 +1,29 @@
# joint inversion
This is a toy model to simultaneously update model parameters and locate earthquakes (Figure 8e.)
Reference:
[1] J. Chen, M. Nagaso, M. Xu, and P. Tong, TomoATT: An open-source package for Eikonal equation-based adjoint-state traveltime tomography for seismic velocity and azimuthal anisotropy, submitted.
https://doi.org/10.48550/arXiv.2412.00031
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.
2. After inversion, run `plot_output.py` to plot the results.
The initial and true models:
![](img/model_setting.jpg)
The inversion results:
![](img/model_joint.jpg)

View File

@@ -0,0 +1,34 @@
from pytomoatt.src_rec import SrcRec
class AssignNoise:
def __init__(self, in_fname, out_fname):
self.in_fname = in_fname
self.out_fname = out_fname
self.sr = SrcRec.read(self.in_fname)
def assign_noise_for_tt(self, noise_level=0.1):
self.sr.add_noise(noise_level)
def assign_noise_for_src(self, lat_pert=0.1, lon_pert=0.1, dep_pert=10, tau_pert=0.5):
self.sr.add_noise_to_source(lat_pert, lon_pert, dep_pert, tau_pert)
if __name__ == "__main__":
in_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward.dat" # input source receiver file
out_fname = "OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat" # output source receiver file
sigma = 0.1 # noise level in seconds
lat_pert = 0.1 # assign noise for latitude in degrees
lon_pert = 0.1 # assign noise for longitude in degrees
dep_pert = 10 # assign noise for depth in km
tau_pert = 0.5 # assign noise for origin time in seconds
# Initialize the instance
an = AssignNoise(in_fname, out_fname)
# Assign noise for travel time
an.assign_noise_for_tt(sigma)
# Assign noise for source
an.assign_noise_for_src(lat_pert, lon_pert, dep_pert, tau_pert)
# Write the output file
an.sr.write(out_fname)

View File

@@ -0,0 +1,286 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
import os
# %%
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# read models
Ngrid = [61,61,61]
data_file = '2_models/model_init_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
par_file = '3_input_params/input_params_signal.yaml'
model = ATTModel.read(data_file, par_file)
initial_model = model.to_xarray()
data_file = '2_models/model_ckb_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
model = ATTModel.read(data_file, par_file)
ckb_model = model.to_xarray()
# initial model
depth = 10.0
vel_init = initial_model.interp_dep(depth, field='vel')
start = [1.25,0]; end = [1.25,2]
vel_init_sec = initial_model.interp_sec(start, end, field='vel', val = 1)
# checkerboard model
vel_ckb = ckb_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
vel_ckb_sec = ckb_model.interp_sec(start, end, field='vel', val = 1)
# anisotropic arrow
samp_interval = 3
length = 7
width = 0.1
ani_thd = 0.02
ani_ckb_phi = ckb_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_ckb_epsilon = ckb_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_ckb = np.hstack([ani_ckb_phi, ani_ckb_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_ckb_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_ckb_epsilon[:,2] > ani_thd)
ani_ckb = ani_ckb[idx[0],:]
try:
os.mkdir('img')
except:
pass
# %%
# read src_rec_file for data
from pytomoatt.src_rec import SrcRec
sr = SrcRec.read('1_src_rec_files/src_rec_config.dat')
station = sr.receivers[['stlo','stla','stel']].values.T
true_loc = sr.sources[['evlo','evla','evdp']].values.T
earthquake = true_loc
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_signal/src_rec_file_forward_errloc.dat')
init_loc = sr.sources[['evlo','evla','evdp']].values.T
# %%
# categorize earthquakes
ev_idx1 = []
ev_idx2 = []
ev_idx3 = []
for i in range(earthquake.shape[1]):
dep = earthquake[2,i]
if dep < 15:
ev_idx1.append(i)
elif dep < 25:
ev_idx2.append(i)
elif dep < 35:
ev_idx3.append(i)
# %%
# plot the model setting
fig = pygmt.Figure()
region = [0,2,0,2]
frame = ["xa1","ya1"]
projection = "M10c"
spacing = 0.04
vel_range = 20
# -------------- initial model and earthquake location --------------
fig.basemap(region=region, frame=["xa1","ya1","+tInitial model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_init[:,0]; y = vel_init[:,1]; value = (vel_init[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = init_loc[0,ev_idx1], y = init_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = init_loc[0,ev_idx2], y = init_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = init_loc[0,ev_idx3], y = init_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
fig.plot(x = station[0,:], y = station[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# # anisotropic arrow
# fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_init_sec[:,3]; y = vel_init_sec[:,1]; value = (vel_init_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = init_loc[2,ev_idx1], y = init_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = init_loc[2,ev_idx2], y = init_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = init_loc[2,ev_idx3], y = init_loc[1,ev_idx3], style = "c0.1c", fill = "black")
fig.shift_origin(xshift=4)
# -------------- true model and earthquake location --------------
fig.basemap(region=region, frame=["xa1","ya1","+tTrue model and locations"], projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
x = vel_ckb[:,0]; y = vel_ckb[:,1]; value = (vel_ckb[:,2] - vel_init[:,2])/vel_init[:,2] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = true_loc[0,ev_idx1], y = true_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = true_loc[0,ev_idx2], y = true_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = true_loc[0,ev_idx3], y = true_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
fig.plot(ani_ckb, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
x = vel_ckb_sec[:,3]; y = vel_ckb_sec[:,1]; value = (vel_ckb_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
grid = pygmt.surface(x=x, y=y, z=value, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = true_loc[2,ev_idx1], y = true_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = true_loc[2,ev_idx2], y = true_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = true_loc[2,ev_idx3], y = true_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_setting.png', dpi=300)
# %%
# plot the joint inversion results
fig = pygmt.Figure()
region = [0,2,0,2]
projection = "M10c"
spacing = 0.04
vel_range = 20
tag_list = ["joint_step1", "joint_step2", "joint_step3"]
for itag, tag in enumerate(tag_list):
if (tag == "joint_step1"):
# model
x = vel_init[:,0]; y = vel_init[:,1]; value = (vel_init[:,2] - vel_init[:,2])/vel_init[:,2] * 100
x_sec = vel_init_sec[:,3]; y_sec = vel_init_sec[:,1]; value_sec = (vel_init_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
# location
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_%s/src_rec_file_reloc_0050.dat'%(tag))
re_loc = sr.sources[['evlo','evla','evdp']].values.T
frame = ["xa1","ya1","+tStep %d, preliminary location"%(itag+1)]
elif (tag == "joint_step2"):
# model
data_file = "OUTPUT_FILES/OUTPUT_FILES_%s/final_model.h5"%(tag)
model = ATTModel.read(data_file, par_file)
inv_model = model.to_xarray()
vel_inv = inv_model.interp_dep(depth, field='vel') # lon = [:,0], lat = [:,1], vel = [:,2]
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
vel_inv_sec = inv_model.interp_sec(start, end, field='vel', val = 1)
x_sec = vel_inv_sec[:,3]; y_sec = vel_inv_sec[:,1]; value_sec = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
ani_inv_phi = inv_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_inv_epsilon = inv_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_inv = np.hstack([ani_inv_phi, ani_inv_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_inv_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_inv_epsilon[:,2] > ani_thd)
ani = ani_inv[idx[0],:]
# location
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_%s/src_rec_file_inv_0039_reloc_0039.dat'%(tag))
re_loc = sr.sources[['evlo','evla','evdp']].values.T
frame = ["xa1","ya1","+tStep %d, joint inversion"%(itag+1)]
elif (tag == "joint_step3"):
# model
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
x_sec = vel_inv_sec[:,3]; y_sec = vel_inv_sec[:,1]; value_sec = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100
ani = ani_inv[idx[0],:]
# location
sr = SrcRec.read('OUTPUT_FILES/OUTPUT_FILES_%s/src_rec_file_reloc_0100.dat'%(tag))
re_loc = sr.sources[['evlo','evla','evdp']].values.T
frame = ["xa1","ya1","+tStep %d, relocation"%(itag+1)]
# plot the inversion result
# -------------- inversion model --------------
fig.basemap(region=region, frame=frame, projection=projection)
# velocity perturbation
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-vel_range, vel_range], background=True, reverse=False)
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = re_loc[0,ev_idx1], y = re_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = re_loc[0,ev_idx2], y = re_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = re_loc[0,ev_idx3], y = re_loc[1,ev_idx3], style = "c0.1c", fill = "black")
# stations
# fig.plot(x = loc_st[0,:], y = loc_st[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# anisotropic arrow
if (tag == "joint_step2" or tag == "joint_step3"):
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.shift_origin(xshift=11)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","Nswe"], projection="X2c/10c")
grid = pygmt.surface(x=x_sec, y=y_sec, z=value_sec, spacing="1/0.04",region=[0,40,0,2])
fig.grdimage(grid = grid)
# earthquakes
fig.plot(x = re_loc[2,ev_idx1], y = re_loc[1,ev_idx1], style = "c0.1c", fill = "red")
fig.plot(x = re_loc[2,ev_idx2], y = re_loc[1,ev_idx2], style = "c0.1c", fill = "green")
fig.plot(x = re_loc[2,ev_idx3], y = re_loc[1,ev_idx3], style = "c0.1c", fill = "black")
fig.shift_origin(xshift=4)
# ------------------- colorbar -------------------
fig.shift_origin(xshift=-4)
fig.shift_origin(xshift=-11, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(vel_range),"x+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=6, yshift=-1)
fig.basemap(region=[0,1,0,1], frame=["wesn"], projection="X6c/1.5c")
ani = [
[0.2, 0.6, 45, 0.02*length, width], # lon, lat, phi, epsilon, size
[0.5, 0.6, 45, 0.05*length, width],
[0.8, 0.6, 45, 0.10*length, width],
]
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black')
fig.text(text=["0.02", "0.05", "0.10"], x=[0.2,0.5,0.8], y=[0.2]*3, font="16p,Helvetica", justify="CM")
fig.shift_origin(xshift= 11, yshift=2.5)
fig.show()
fig.savefig('img/model_joint.png', dpi=300)

View File

@@ -0,0 +1,63 @@
# download src_ref_files from Zenodo
import os
import numpy as np
import sys
try:
from pytomoatt.model import ATTModel
from pytomoatt.checkerboard import Checker
from pytomoatt.src_rec import SrcRec
except:
print("ERROR: ATTModel not found. Please install pytomoatt first."
"See https://tomoatt.github.io/PyTomoATT/installation.html for details.")
sys.exit(1)
class BuildInitialModel():
def __init__(self, par_file="./3_input_params/input_params_signal.yaml", output_dir="2_models"):
"""
Build initial model for tomography inversion
"""
self.am = ATTModel(par_file)
self.output_dir = output_dir
def build_initial_model(self, vel_min=5.0, vel_max=8.0):
"""
Build initial model for tomography inversion
"""
self.am.vel[self.am.depths < 0, :, :] = vel_min
idx = np.where((0 <= self.am.depths) & (self.am.depths < 40.0))[0]
self.am.vel[idx, :, :] = np.linspace(vel_min, vel_max, idx.size)[::-1][:, np.newaxis, np.newaxis]
self.am.vel[self.am.depths >= 40.0, :, :] = vel_max
def build_ckb_model(output_dir="2_models"):
cbk = Checker(f'{output_dir}/model_init_N61_61_61.h5', para_fname="./3_input_params/input_params_signal.yaml")
cbk.checkerboard(
n_pert_x=2, n_pert_y=2, n_pert_z=2,
pert_vel=0.2, pert_ani=0.1, ani_dir=60.0,
lim_x=[0.5, 1.5], lim_y=[0.5, 1.5], lim_z=[0, 40]
)
cbk.write(f'{output_dir}/model_ckb_N61_61_61.h5')
if __name__ == "__main__":
# download src_rec_config.dat
url = 'https://zenodo.org/records/14053821/files/src_rec_config.dat'
path = "1_src_rec_files/src_rec_config.dat"
os.makedirs(os.path.dirname(path), exist_ok=True)
if not os.path.exists(path):
sr = SrcRec.read(url)
sr.write(path)
# build initial model
output_dir = "2_models"
os.makedirs(output_dir, exist_ok=True)
bim = BuildInitialModel(output_dir=output_dir)
bim.build_initial_model()
bim.am.write('{}/model_init_N{:d}_{:d}_{:d}.h5'.format(bim.output_dir, *bim.am.n_rtp))
# build ckb model
build_ckb_model(output_dir)

View File

@@ -0,0 +1,40 @@
#!/bin/bash
# Step 1: Generate necessary input files
python prepare_input_files.py
# Step 2: Run forward modeling
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_signal.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_signal.yaml
# Step 3: Assign data noise and location perturbation to the observational data
python assign_gaussian_noise.py
# Step 4: Do joint inversion
# # for WSL
# # step 1. relocation for 50 iterations in the initial model, using traveltimes and common-receiver differential arrival times
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step1.yaml
# # step 2. simultaneously update model parameters and locations for 40 iterations,
# # using traveltimes and common-source differential arrival times for model update
# # using traveltimes and common-receiver differential arrival times for location
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step2.yaml
# # step 3. relocation for 50 iterations in the initial model, using only common-receiver differential arrival times
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step3.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step1.yaml
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step2.yaml
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_joint_step3.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_joint_step1.yaml
mpirun -n 8 TOMOATT -i 3_input_params/input_params_joint_step2.yaml
mpirun -n 8 TOMOATT -i 3_input_params/input_params_joint_step3.yaml
# Step 5 (Optional): Plot the results
python plot_output.py

View File

@@ -0,0 +1,215 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: OUTPUT_FILES/OUTPUT_FILES_1dinv_signal/src_rec_file_step_0000.dat # source receiver file path
swap_src_rec: true # swap source and receiver (only valid for regional source and receiver, those of tele remain unchanged)
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N61_61_61.h5 # path to initial model file
# model_1d_name: dummy_model_1d_name # 1D model name used in teleseismic 2D solver (iasp91, ak135, user_defined is available), defined in include/1d_model.h
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
nproc_sub: 1 # number of processors for sweep parallelization (parallel the fast sweep method)
use_gpu: false # true if use gpu (EXPERIMENTAL)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_1dinv_inv # path to output director (default is ./OUTPUT_FILES/)
output_source_field: true # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false # True: output sensitivity kernel and kernel density. Default: false. File: 'out_data_sim_group_X'.
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do).
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 4
have_tele_data: false # An error will be reported if false but source out of study region is used. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 200 # maximum number of inversion iterations
optim_method: 0 # optimization method. 0 : grad_descent, 1 : halve-stepping, 2 : lbfgs (EXPERIMENTAL)
#common parameters for all optim methods
step_length: 0.02 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
step_method: 1 # the method to modulate step size. 0: according to objective function; 1: according to gradient direction
# if step_method:0. if objective function increase, step size -> step length * step_length_decay.
step_length_decay: 0.9 # default: 0.9
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.2] # default: [0.5,1.2]
# Kdensity_coe is used to rescale the final kernel: kernel -> kernel / pow(density of kernel, Kdensity_coe). if Kdensity_coe > 0, the region with less data will be enhanced during the inversion
# e.g., if Kdensity_coe = 0, kernel remains upchanged; if Kdensity_coe = 1, kernel is fully normalized. 0.5 or less is recommended if really required.
Kdensity_coe: 0 # default: 0.0, limited range: 0.0 - 0.95
# smoothing
smoothing:
smooth_method: 0 # 0: multiparametrization, 1: laplacian smoothing (EXPERIMENTAL)
l_smooth_rtp: [1, 1, 1] # smoothing coefficients for laplacian smoothing
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: true # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: true # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: true # true if use uniform inversion grid for lon, false if use flexible inversion grid
# -------------- uniform inversion grid setting --------------
# settings for uniform inversion grid
n_inv_dep_lat_lon: [13, 9, 9] # number of the base inversion grid points
min_max_dep_inv: [-10, 50] # depth in km (Radius of the earth is defined in config.h/R_earth)
min_max_lat_inv: [0, 2] # latitude in degree
min_max_lon_inv: [0, 2] # longitude in degree
# -------------- flexible inversion grid setting --------------
# settings for flexible inversion grid
dep_inv: [-10, 0, 10, 20, 30, 40, 50, 60] # inversion grid for vel in depth (km)
lat_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in latitude (degree)
lon_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# In the following data subsection, XXX_weight means a weight is assigned to the data, influencing the objective function and gradient
# XXX_weight : [d1,d2,w1,w2] means:
# if XXX < d1, weight = w1
# if d1 <= XXX < d2, weight = w1 + (XXX-d1)/(d2-d1)*(w2-w1), (linear interpolation)
# if d2 <= XXX , weight = w2
# You can easily set w1 = w2 = 1.0 to normalize the weight related to XXX.
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: true # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight: [100, 200, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: false # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: false # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_weight: 1 # weight of absolute traveltime data after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data after balance, default: 1.0
teleseismic_weight: 1 # weight of teleseismic data after balance, default: 1.0 (exclude in this version)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : false # update azimuthal anisotropy (xi, eta) or not. default: false

View File

@@ -0,0 +1,215 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 2] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 61, 61] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_config.dat # source receiver file path
swap_src_rec: true # swap source and receiver (only valid for regional source and receiver, those of tele remain unchanged)
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_61_61.h5 # path to initial model file
# model_1d_name: dummy_model_1d_name # 1D model name used in teleseismic 2D solver (iasp91, ak135, user_defined is available), defined in include/1d_model.h
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
nproc_sub: 1 # number of processors for sweep parallelization (parallel the fast sweep method)
use_gpu: false # true if use gpu (EXPERIMENTAL)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_1dinv_signal # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false # True: output sensitivity kernel and kernel density. Default: false. File: 'out_data_sim_group_X'.
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do).
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 4
have_tele_data: false # An error will be reported if false but source out of study region is used. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 1 # maximum number of inversion iterations
optim_method: 0 # optimization method. 0 : grad_descent, 1 : halve-stepping, 2 : lbfgs (EXPERIMENTAL)
#common parameters for all optim methods
step_length: 0.02 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
step_method: 1 # the method to modulate step size. 0: according to objective function; 1: according to gradient direction
# if step_method:0. if objective function increase, step size -> step length * step_length_decay.
step_length_decay: 0.9 # default: 0.9
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.2] # default: [0.5,1.2]
# Kdensity_coe is used to rescale the final kernel: kernel -> kernel / pow(density of kernel, Kdensity_coe). if Kdensity_coe > 0, the region with less data will be enhanced during the inversion
# e.g., if Kdensity_coe = 0, kernel remains upchanged; if Kdensity_coe = 1, kernel is fully normalized. 0.5 or less is recommended if really required.
Kdensity_coe: 0 # default: 0.0, limited range: 0.0 - 0.95
# smoothing
smoothing:
smooth_method: 0 # 0: multiparametrization, 1: laplacian smoothing (EXPERIMENTAL)
l_smooth_rtp: [1, 1, 1] # smoothing coefficients for laplacian smoothing
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: true # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: true # true if use uniform inversion grid for lon, false if use flexible inversion grid
# -------------- uniform inversion grid setting --------------
# settings for uniform inversion grid
n_inv_dep_lat_lon: [12, 9, 9] # number of the base inversion grid points
min_max_dep_inv: [-10, 50] # depth in km (Radius of the earth is defined in config.h/R_earth)
min_max_lat_inv: [0, 2] # latitude in degree
min_max_lon_inv: [0, 2] # longitude in degree
# -------------- flexible inversion grid setting --------------
# settings for flexible inversion grid
dep_inv: [-10, 0, 10, 20, 30, 40, 50, 60] # inversion grid for vel in depth (km)
lat_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in latitude (degree)
lon_inv: [30, 30.2, 30.4, 30.6, 30.8, 31, 31.2, 31.4, 31.6, 31.8, 32] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# In the following data subsection, XXX_weight means a weight is assigned to the data, influencing the objective function and gradient
# XXX_weight : [d1,d2,w1,w2] means:
# if XXX < d1, weight = w1
# if d1 <= XXX < d2, weight = w1 + (XXX-d1)/(d2-d1)*(w2-w1), (linear interpolation)
# if d2 <= XXX , weight = w2
# You can easily set w1 = w2 = 1.0 to normalize the weight related to XXX.
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: true # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the absolute traveltime residual (second) = abs(t^{obs}_{n,i} - t^{syn}_{n,j})
distance_weight: [100, 200, 1, 1] # XXX is epicenter distance (km) between the source and receiver related to the data
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: false # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common source differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{n,j} - t^{syn}_{n,i} + t^{syn}_{n,j}).
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate stations related to the common source.
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
residual_weight: [1, 3, 1, 1] # XXX is the common receiver differential traveltime residual (second) = abs(t^{obs}_{n,i} - t^{obs}_{m,i} - t^{syn}_{n,i} + t^{syn}_{m,i})
azimuthal_weight: [15, 30, 1, 1] # XXX is the azimuth difference between two separate sources related to the common receiver.
# -------------- global weight of different types of data (to balance the weight of different data) --------------
global_weight:
balance_data_weight: false # yes: over the total weight of the each type of the data. no: use original weight (below weight for each type of data needs to be set)
abs_time_weight: 1 # weight of absolute traveltime data after balance, default: 1.0
cs_dif_time_local_weight: 1 # weight of common source differential traveltime data after balance, default: 1.0
cr_dif_time_local_weight: 1 # weight of common receiver differential traveltime data after balance, default: 1.0
teleseismic_weight: 1 # weight of teleseismic data after balance, default: 1.0 (exclude in this version)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : false # update azimuthal anisotropy (xi, eta) or not. default: false

View File

@@ -0,0 +1,37 @@
import h5py
import matplotlib.pyplot as plt
import numpy as np
import os
try:
os.mkdir("img")
except:
pass
dep = np.linspace(50,-10, 61)
with h5py.File("OUTPUT_FILES/OUTPUT_FILES_1dinv_inv/final_model.h5", "r") as f:
vel_final= np.array(f["vel"])
with h5py.File("2_models/model_init_N61_61_61.h5", "r") as f:
vel_init = np.array(f["vel"])
with h5py.File("2_models/model_ckb_N61_61_61.h5", "r") as f:
vel_ckb = np.array(f["vel"])
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(111)
ax.plot(vel_init[:,0,0] , dep, label="init")
ax.plot(vel_ckb[:,0,0], dep, label="ckb")
ax.plot(vel_final[:,0,0], dep, label="inv")
ax.grid()
ax.set_xlabel("Velocity (m/s)",fontsize=16)
ax.set_ylabel("Depth (km)",fontsize=16)
ax.get_xaxis().set_tick_params(labelsize=16)
ax.get_yaxis().set_tick_params(labelsize=16)
ax.set_xlim([4.5,8.5])
ax.set_ylim([0,50])
plt.gca().invert_yaxis()
plt.legend(fontsize=16)
plt.show()
fig.savefig("img/1d_model_inversion.png", dpi=300, bbox_inches="tight", edgecolor="w", facecolor="w")

View File

@@ -0,0 +1,64 @@
# %%
# download src_ref_files from Zenodo
import os
import numpy as np
import sys
try:
from pytomoatt.model import ATTModel
from pytomoatt.checkerboard import Checker
from pytomoatt.src_rec import SrcRec
except:
print("ERROR: ATTModel not found. Please install pytomoatt first."
"See https://tomoatt.github.io/PyTomoATT/installation.html for details.")
sys.exit(1)
class BuildInitialModel():
def __init__(self, par_file="./3_input_params/input_params_signal.yaml", output_dir="2_models"):
"""
Build initial model for tomography inversion
"""
self.am = ATTModel(par_file)
self.output_dir = output_dir
def build_initial_model(self, vel_min=5.0, vel_max=8.0):
"""
Build initial model for tomography inversion
"""
self.am.vel[self.am.depths < 0, :, :] = vel_min
idx = np.where((0 <= self.am.depths) & (self.am.depths < 40.0))[0]
self.am.vel[idx, :, :] = np.linspace(vel_min, vel_max, idx.size)[::-1][:, np.newaxis, np.newaxis]
self.am.vel[self.am.depths >= 40.0, :, :] = vel_max
def build_ckb_model(self):
"""
Build checkerboard model for tomography inversion
"""
nr = self.am.n_rtp[0]
for ir in range(nr):
dep = self.am.depths[ir]
self.am.vel[ir, :, :] = (1 + 0.05 * np.sin(np.pi * dep / 10.0)) * self.am.vel[ir, :, :]
if __name__ == "__main__":
# download src_rec_config.dat
url = 'https://zenodo.org/records/14053821/files/src_rec_config.dat'
path = "1_src_rec_files/src_rec_config.dat"
os.makedirs(os.path.dirname(path), exist_ok=True)
if not os.path.exists(path):
sr = SrcRec.read(url)
sr.write(path)
# build initial model
output_dir = "2_models"
os.makedirs(output_dir, exist_ok=True)
bim = BuildInitialModel(output_dir=output_dir)
bim.build_initial_model()
bim.am.write('{}/model_init_N{:d}_{:d}_{:d}.h5'.format(bim.output_dir, *bim.am.n_rtp))
bim.build_ckb_model()
bim.am.write('{}/model_ckb_N{:d}_{:d}_{:d}.h5'.format(bim.output_dir, *bim.am.n_rtp))

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Step 1: Generate necessary input files
echo "Generating TomoATT input files..."
python prepare_input_files.py
# Step 2: Run forward modeling
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_1dinv_signal.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_1dinv_signal.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_1dinv_signal.yaml
# Step 3: Do inversion
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_1dinv_inv.yaml
# # for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_1dinv_inv.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_1dinv_inv.yaml
# Step 4 (Optional): Plot the results
echo "Plotting the results..."
python plot_output.py

Binary file not shown.

View File

@@ -0,0 +1,186 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-5, 45] # depth in km
min_max_lat: [-2.0, 2.4] # latitude in degree
min_max_lon: [-0.8, 0.8] # longitude in degree
n_rtp: [51, 89, 33] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_file.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N51_89_33.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_inv # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: true
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: true # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: true # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: true # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do)
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 1
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 80 # maximum number of inversion iterations
step_length: 0.01 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.41] # default: [0.5,1.2]
Kdensity_coe: 0.3 # default: 0.0, range: 0.0 - 1.0
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: false # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: false # true if use uniform inversion grid for lon, false if use flexible inversion grid
# settings for uniform inversion grid
n_inv_dep_lat_lon: [3, 11, 11] # number of inversion grid in depth, latitude, and longitude direction
min_max_dep_inv: [-5 , 5] # inversion grid for vel in depth (km)
min_max_lat_inv: [0, 1] # inversion grid for vel in latitude (degree)
min_max_lon_inv: [0, 1] # inversion grid for vel in longitude (degree)
# settings for flexible inversion grid
dep_inv: [-5, -2, 0, 3, 7, 12, 17, 23, 30, 38, 47, 57] # inversion grid for vel in depth (km)
lat_inv: [-2.5, -2.2, -1.9, -1.6, -1.3, -1.0, -0.7, -0.4, -0.1, 0.2, 0.5, 0.8, 1.1, 1.4, 1.7, 2.0, 2.3, 2.6] # inversion grid for vel in latitude (degree)
lon_inv: [-1.2, -0.9, -0.6, -0.3, 0, 0.3, 0.6, 0.9, 1.2] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# if we want to use another inversion grid for inverting anisotropy, set invgrid_ani: true (default: false)
invgrid_ani: true
# ---------- flexible inversion grid setting for anisotropy ----------
# settings for flexible inversion grid for anisotropy
dep_inv_ani: [-5, -2, 0, 3, 7, 12, 17, 23, 30, 38, 47, 57] # inversion grid for ani in depth (km)
lat_inv_ani: [-2.8, -2.3, -1.8, -1.3, -0.8, -0.3, 0.2, 0.7, 1.2, 1.7, 2.2, 2.7] # inversion grid for ani in latitude (degree)
lon_inv_ani: [-1.2, -0.9, -0.6, -0.3, 0, 0.3, 0.6, 0.9, 1.2] # inversion grid for ani in longitude (degree)
trapezoid_ani: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: true # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: false # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : true # update azimuthal anisotropy (xi, eta) or not. default: false

View File

@@ -0,0 +1,30 @@
# Real case of regional tomography in central California near Parkfield
This is a real case to invert traveltimes for velocity heterogeneity and azimuthal anisotropy in central California near Parkfield
Reference:
[1] J. Chen, G. Chen, M. Nagaso, and P. Tong, Adjoint-state traveltime tomography for azimuthally anisotropic media in spherical coordinates. Geophys. J. Int., 234 (2023), pp. 712-736.
https://doi.org/10.1093/gji/ggad093
[2] J. Chen, M. Nagaso, M. Xu, and P. Tong, TomoATT: An open-source package for Eikonal equation-based adjoint-state traveltime tomography for seismic velocity and azimuthal anisotropy, submitted.
https://doi.org/10.48550/arXiv.2412.00031
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.
2. After inversion, run `plot_output.py` to plot the results.
The imaging results:
![](img/imaging_result.jpg)

View File

@@ -0,0 +1,222 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
import os
# %%
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# read model files
Ngrid = [51,89,33]
data_file = '2_models/model_init_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
par_file = '3_input_params/input_params_real.yaml'
model = ATTModel.read(data_file, par_file)
initial_model = model.to_xarray()
data_file = 'OUTPUT_FILES/OUTPUT_FILES_real/final_model.h5'
model = ATTModel.read(data_file, par_file)
inv_model = model.to_xarray()
# %%
# read earthquakes and stations
from pytomoatt.src_rec import SrcRec
# read src_rec_file
sr = SrcRec.read("1_src_rec_files/src_rec_file.dat")
# rotate back to original coordinates
central_lat = 35.6
central_lon = -120.45
rotation_angle = -30
sr.rotate(central_lat, central_lon, rotation_angle, reverse=True)
# get the coordinates of the stations and earthquakes
stations = sr.receivers[['stlo','stla','stel']].values.T
earthquakes = sr.sources[['evlo','evla','evdp']].values.T
print(stations.shape)
print(earthquakes.shape)
# %%
# study region
import sys
sys.path.append('../utils')
import functions_for_data as ffd
lat1 = -1.8; lat2 = 2.2;
lon1 = -0.7; lon2 = 0.7;
lat_lon_rotate = np.array([[lon1,lat1],[lon1,lat2],[lon2,lat2],[lon2,lat1],[lon1,lat1]])
lat_lon = ffd.rtp_rotation_reverse(lat_lon_rotate[:,1],lat_lon_rotate[:,0],central_lat,central_lon,rotation_angle)
studt_lat = lat_lon[0]
studt_lon = lat_lon[1]
# %%
# load topography
region = [-122.8,-118.5,33.5,38]
grid_topo = pygmt.datasets.load_earth_relief(resolution="01m", region=region)
grid_gra = pygmt.grdgradient(grid = grid_topo, azimuth = 0)
# %%
def line_read(file):
doc=open(file,'r')
file = doc.readlines()
doc.close()
lat = []; lon = [];
for info in file:
tmp = info.split()
lon.append(float(tmp[0]))
lat.append(float(tmp[1]))
return((lat,lon))
# %%
# plot imgaing results
fig = pygmt.Figure()
try:
os.mkdir("img")
except:
pass
# ------------------ Sub fig 1. topography ------------------
region = [-122.8,-118.5,33.5,38]
frame = ["xa1","ya1","nSWe"]
projection = "M10c"
# topography
pygmt.makecpt(cmap="globe", series=[-4000,4000], background = True)
fig.grdimage(grid=grid_topo, shading = grid_gra, projection=projection, frame=frame,region=region)
# study region
fig.plot(x = studt_lon, y = studt_lat, pen = "1.5p,red")
# earthquakes
fig.plot(x = earthquakes[0,:], y = earthquakes[1,:], style = "c0.02c", fill = "red",label = "Earthquake")
# stations
fig.plot(x = stations[0,:], y = stations[1,:], style = "t0.2c", fill = "blue", pen = "white", label = "Station")
fig.basemap(region=[0,1,0,1], frame=["wesn+gwhite"], projection="X4c/2c")
fig.plot(x=0.1, y=0.3, style='c0.2c', fill='red')
fig.text(text="Earthquake", x=0.2, y=0.3, font="16p,Helvetica", justify="LM")
fig.plot(x=0.1, y=0.7, style='t0.4c', fill='blue', pen='black')
fig.text(text="Station", x=0.2, y=0.7, font="16p,Helvetica", justify="LM")
# ------------------ Sub fig 2. colorbar ------------------
fig.shift_origin(xshift= 2, yshift= -2)
pygmt.makecpt(cmap="globe", series=[-4000,4000], background = True)
fig.colorbar(frame = ["a%f"%(4000),"y+lElevation (m)"], position="+e+w4c/0.3c+h")
fig.shift_origin(yshift=-2)
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-8, 8], background=True, reverse=False)
fig.colorbar(frame = ["a%f"%(4),"y+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(yshift=-2)
pygmt.makecpt(cmap="cool", series=[0, 0.08], background=True, reverse=False)
fig.colorbar(frame = ["a%f"%(0.04),"y+lAnisotropy"], position="+ef+w4c/0.3c+h")
# ------------------ Sub fig 3. model ------------------
fig.shift_origin(xshift = 10, yshift=8)
region_oblique = [-0.7,0.7,-2.2,1.8]
projection = "OA%s/%s/%s/4c"%(central_lon,central_lat,rotation_angle-90.0)
perspective = "30/90"
spacing = "1m"
depth_list = [4,8,16]
for idepth, depth in enumerate(depth_list):
# initial model
vel_init = initial_model.interp_dep(depth, field='vel')
# output model
vel_inv = inv_model.interp_dep(depth, field='vel') # velocity
epsilon_inv = inv_model.interp_dep(depth, field='epsilon') # magnitude of anisotropy
# fast velocity directions
samp_interval = 3
ani_thd = 0.015
length = 20
width = 0.1
ani_inv_phi = inv_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_inv_epsilon = inv_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_inv = np.hstack([ani_inv_phi, ani_inv_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_inv_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_inv_epsilon[:,2] > ani_thd)
ani = ani_inv[idx[0],:]
# --------- plot velocity ------------
if idepth == 0:
frame = ["xa100","ya1","nSwE"]
elif idepth == len(depth_list)-1:
frame = ["xa100","ya1","NsWe"]
else:
frame = ["xa100","ya1","nswe"]
fig.basemap(region=region_oblique, frame=frame, projection=projection, perspective=perspective)
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-8, 8], background=True, reverse=False)
x = vel_init[:,0]; y = vel_init[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100
y,x = ffd.rtp_rotation_reverse(y,x,central_lat,central_lon,rotation_angle)
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(frame=frame,grid = grid,projection=projection, region=region_oblique,perspective=perspective) # nan_transparent may work
# tectonic setting
fig.coast(region=region_oblique, frame=frame, projection=projection, perspective=perspective, shorelines="1p,black") # coastlines
(SAFy,SAFx) = line_read("tectonics/SAF")
fig.plot(x = SAFx, y = SAFy, pen = '3.0p,black', perspective = perspective) # SAF
if idepth == 0:
fig.text(text = "SMB", x = -120.45 , y = 35.0, font = "16p,Helvetica-Bold,black", angle = 150, fill = "lightblue", perspective = perspective) # SMB
fig.text(text = "FT", x = -120.6 , y = 36.50, font = "16p,Helvetica-Bold,black", angle = 150, fill = "lightblue", perspective = perspective) # Franciscan terrane
fig.text(text = "ST", x = -121.1 , y = 36.0, font = "16p,Helvetica-Bold,black", angle = 150, fill = "lightblue", perspective = perspective) # Salinian terrane
fig.text(text = "TR", x = -119.30 , y = 34.70, font = "16p,Helvetica-Bold,black", angle = 150, fill = "lightblue", perspective = perspective) # Coast Ranges
# depth label
fig.text(text="%d km"%(depth), x = -119.8 , y = 34.0, font = "16p,Helvetica-Bold,black", angle = 180, fill = "white", perspective = perspective) # Coast Ranges
# --------- plot anisotropy ------------
fig.shift_origin(yshift=-12)
fig.basemap(region=region_oblique, frame=frame, projection=projection, perspective=perspective)
pygmt.makecpt(cmap="cool", series=[0, 0.08], background=True)
value = epsilon_inv[:,2]
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(frame=frame,grid = grid,projection=projection, region=region_oblique,perspective=perspective) # nan_transparent may work
# tectonic setting
fig.coast(region=region_oblique, frame=frame, projection=projection, perspective=perspective, shorelines="1p,black") # coastlines
(line_y,line_x) = line_read("tectonics/SAF_creeping")
fig.plot(x = line_x, y = line_y, pen = '3.0p,black',perspective = perspective)
(line_y,line_x) = line_read("tectonics/SAF_transition")
fig.plot(x = line_x, y = line_y, pen = '3.0p,red',perspective = perspective)
(line_y,line_x) = line_read("tectonics/SAF_locked")
fig.plot(x = line_x, y = line_y, pen = '3.0p,blue',perspective = perspective)
# anisotropy
if len(ani) > 0:
# rotate back to original coordinates
x = ani[:,0]; y = ani[:,1]
y,x = ffd.rtp_rotation_reverse(y,x,central_lat,central_lon,rotation_angle)
ani[:,0] = x; ani[:,1] = y; # no need to modify the angle, because the porjection angle and rotate angle are the same
fig.plot(ani, style='j', fill='yellow1', pen='0.5p,black',perspective=perspective)
fig.shift_origin(xshift=6,yshift=12)
fig.show()
fig.savefig("img/imaging_result.png")

View File

@@ -0,0 +1,45 @@
# %%
# download src_ref_files from Zenodo
import os
import requests
url = 'https://zenodo.org/records/14065341/files/src_rec_file.dat?download=1'
path = "1_src_rec_files/src_rec_file.dat"
# check file existence
if not os.path.exists(path):
try:
os.mkdir("1_src_rec_files")
except:
pass
print("Downloading src_rec_file.dat from Zenodo...")
response = requests.get(url, stream=True)
with open(path, 'wb') as out_file:
out_file.write(response.content)
print("Download complete.")
else:
print("src_rec_file.dat already exists.")
# %%
# download initial model from Zenodo
url = 'https://zenodo.org/records/14065341/files/model_init_N51_89_33.h5?download=1'
path = "2_models/model_init_N51_89_33.h5"
# check file existence
if not os.path.exists(path):
try:
os.mkdir("2_models")
except:
pass
print("Downloading model_init_N51_89_33.h5 from Zenodo...")
response = requests.get(url, stream=True)
with open(path, 'wb') as out_file:
out_file.write(response.content)
print("Download complete.")
else:
print("model_init_N51_89_33.h5 already exists.")

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Step 1: Generate necessary input files
python prepare_input_files.py
# Step 2: Run inversion
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_real.yaml
# for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_real.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_real.yaml
# Step 3 (Optional): Plot the results
python plot_output.py

View File

@@ -0,0 +1,68 @@
-122.73566 37.96894
-122.70941 37.93895
-122.65033 37.88999
-122.62177 37.83209
-122.59009 37.79618
-122.56673 37.74661
-122.51982 37.71281
-122.47924 37.65959
-122.40956 37.58436
-122.38051 37.54962
-122.32748 37.48461
-122.23632 37.38344
-122.18852 37.34638
-122.15621 37.31470
-122.11902 37.26828
-122.01512 37.19501
-121.92424 37.12444
-121.88689 37.10485
-121.86086 37.08276
-121.78342 37.04335
-121.70450 36.97942
-121.65426 36.93801
-121.57487 36.88348
-121.47861 36.81956
-121.43712 36.78821
-121.40534 36.76781
-121.36812 36.75009
-121.33557 36.71495
-121.27255 36.67184
-121.16342 36.57248
-121.09358 36.51578
-121.02139 36.44378
-120.93316 36.35578
-120.79679 36.21978
-120.63636 36.07582
-120.52406 35.97185
-120.43583 35.90791
-120.33957 35.81993
-120.29568 35.74979
-120.26271 35.71512
-120.23380 35.67390
-120.19772 35.63300
-120.12299 35.56383
-120.02674 35.48387
-119.98846 35.44344
-119.88017 35.32590
-119.78610 35.24387
-119.67380 35.14792
-119.53743 35.04400
-119.40726 34.94926
-119.34920 34.92597
-119.31423 34.90995
-119.24588 34.88266
-119.20791 34.87552
-119.16832 34.87107
-119.12954 34.86300
-119.09076 34.86210
-118.97416 34.84129
-118.93565 34.84176
-118.85999 34.82469
-118.78894 34.79661
-118.72217 34.76987
-118.68535 34.75631
-118.56902 34.72084
-118.49005 34.70185
-118.39037 34.66204
-118.22995 34.61434
-118.06150 34.54260

View File

@@ -0,0 +1,10 @@
-121.36812 36.75009
-121.33557 36.71495
-121.27255 36.67184
-121.16342 36.57248
-121.09358 36.51578
-121.02139 36.44378
-120.93316 36.35578
-120.79679 36.21978
-120.63636 36.07582
-120.52406 35.97185

View File

@@ -0,0 +1,10 @@
-120.26271 35.71512
-120.23380 35.67390
-120.19772 35.63300
-120.12299 35.56383
-120.02674 35.48387
-119.98846 35.44344
-119.88017 35.32590
-119.78610 35.24387
-119.67380 35.14792
-119.53743 35.04400

View File

@@ -0,0 +1,5 @@
-120.52406 35.97185
-120.43583 35.90791
-120.33957 35.81993
-120.29568 35.74979
-120.26271 35.71512

Binary file not shown.

View File

@@ -0,0 +1,187 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-50, 550] # depth in km
min_max_lat: [10.5, 22.5] # latitude in degree
min_max_lon: [95.5, 107.5] # longitude in degree
n_rtp: [121, 121, 121] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_file.dat # source receiver file path
swap_src_rec: false # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N121_121_121.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_real # path to output director (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do)
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 1
have_tele_data: true # An error will be reported if false but source out of study region is used. Default: false.
ignore_velocity_discontinuity: true # An error will be reported if false but there is velocity discontinuity (v[ix,iy,iz+1] > v[ix,iy,iz] * 1.2 or v[ix,iy,iz+1] < v[ix,iy,iz] * 0.8) in the input model. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 80 # maximum number of inversion iterations
step_length: 0.01 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.41] # default: [0.5,1.2]
Kdensity_coe: 0.3 # default: 0.0, range: 0.0 - 1.0
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: false # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: false # true if use uniform inversion grid for lon, false if use flexible inversion grid
# settings for flexible inversion grid
dep_inv: [-50, -25, 0, 50, 100, 150, 200, 275, 350, 425, 500, 600,700] # inversion grid for vel in depth (km)
lat_inv: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] # inversion grid for vel in latitude (degree)
lon_inv: [95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# if we want to use another inversion grid for inverting anisotropy, set invgrid_ani: true (default: false)
invgrid_ani: false
# ---------- flexible inversion grid setting for anisotropy ----------
# settings for flexible inversion grid for anisotropy
dep_inv_ani: [-5, -2, 0, 3, 7, 12, 17, 23, 30, 38, 47, 57] # inversion grid for ani in depth (km)
lat_inv_ani: [-2.8, -2.3, -1.8, -1.3, -0.8, -0.3, 0.2, 0.7, 1.2, 1.7, 2.2, 2.7] # inversion grid for ani in latitude (degree)
lon_inv_ani: [-1.2, -0.9, -0.6, -0.3, 0, 0.3, 0.6, 0.9, 1.2] # inversion grid for ani in longitude (degree)
trapezoid_ani: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: false # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: true # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : false # update azimuthal anisotropy (xi, eta) or not. default: false
use_sta_correction: true
# initial_sta_correction_file: 4_initial_station_correct/station_correction_file_step_0010.dat # the path of initial station correction
step_length_sta_correction: 0.01 # step length relate to the update of station correction terms

View File

@@ -0,0 +1,29 @@
# Real case of teleseismic tomography in Thailand and adjacent areas
This is a real case to invert common-source differential arrival times for velocity heterogeneity in Thailand and adjacent areas
Reference:
[1] J. Chen, S. Wu, M. Xu, M. Nagaso, J. Yao, K. Wang, T. Li, Y. Bai, and P. Tong, Adjoint-state teleseismic traveltime tomography: method and application to Thailand in Indochina Peninsula. J.Geophys. Res. Solid Earth, 128(2023), e2023JB027348.
https://doi.org/10.1029/2023JB027348
[2] J. Chen, M. Nagaso, M. Xu, and P. Tong, TomoATT: An open-source package for Eikonal equation-based adjoint-state traveltime tomography for seismic velocity and azimuthal anisotropy, submitted.
https://doi.org/10.48550/arXiv.2412.00031
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.
2. After inversion, run `plot_output.py` to plot the results.
The imaging results:
![](img/imaging_result.jpg)

View File

@@ -0,0 +1,260 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
import os
# %%
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# read model files
Ngrid = [121,121,121]
data_file = '2_models/model_init_N%d_%d_%d.h5'%(Ngrid[0],Ngrid[1],Ngrid[2])
par_file = '3_input_params/input_params_real.yaml'
model = ATTModel.read(data_file, par_file)
init_model = model.to_xarray()
data_file = 'OUTPUT_FILES/OUTPUT_FILES_real/final_model.h5'
model = ATTModel.read(data_file, par_file)
inv_model = model.to_xarray()
# %%
# # read earthquakes and stations
# from pytomoatt.src_rec import SrcRec
# # read src_rec_file
# sr = SrcRec.read("1_src_rec_files/src_rec_file.dat")
# # get the coordinates of the stations and earthquakes
# stations = sr.receivers[['stlo','stla','stel']].values.T
# earthquakes = sr.sources[['evlo','evla','evdp']].values.T
# print(stations.shape)
# print(earthquakes.shape)
# %%
# read earthquakes and stations
import sys
sys.path.append('../utils')
import functions_for_data as ffd
ev, st = ffd.read_src_rec_file('1_src_rec_files/src_rec_file.dat')
# earthquake location
ev_lon, ev_lat, ev_dep , _ = ffd.data_lon_lat_dep_wt_ev(ev)
# station location
st_lon, st_lat, _, _ = ffd.data_lon_lat_ele_wt_st(ev,st)
# %%
# load topography
region = [97,106,12,21]
grid_topo = pygmt.datasets.load_earth_relief(resolution="01m", region=region)
grid_gra = pygmt.grdgradient(grid = grid_topo, azimuth = 0)
# %%
def line_read(file):
doc=open(file,'r')
file = doc.readlines()
doc.close()
lat = []; lon = [];
for info in file:
tmp = info.split()
lon.append(float(tmp[0]))
lat.append(float(tmp[1]))
return((lat,lon))
# %%
# plot imgaing results
fig = pygmt.Figure()
try:
os.mkdir("img")
except:
pass
# ------------------ Sub fig 1. topography ------------------
region = [97,106,12,21]
projection = "B101.5/16.5/12/21/10c"
frame = ["xa2+lLongitude", "ya2+lLatitude", "nSWe"]
spacing = [0.1, 0.1]
# topography
pygmt.makecpt(cmap="globe", series=[-4000,4000], background = True)
fig.grdimage(grid=grid_topo, shading = grid_gra, projection=projection, frame=frame,region=region)
# station
fig.plot(x = st_lon, y = st_lat, style = "t0.4c", fill = "blue", pen = "1p,white", label = "Station")
# tectonic setting
(lat,lon) = line_read('tectonics/Khorat_new.txt') # Khorat Plateau
fig.plot(x = lon, y = lat, pen = "1p,black")
fig.text(text = "Khorat", x = 103.5, y = 17.5, font = "15p,Helvetica-Bold,black", angle = 0)
fig.text(text = "Plateau", x = 103.5, y = 16.5, font = "15p,Helvetica-Bold,black", angle = 0)
(lat,lon) = line_read('tectonics/WangChaoFault.txt') # Wang-Chao Fault
fig.plot(x = lon, y = lat, pen = "1p,black,-")
fig.text(text = "WCF", x = 100, y = 16, font = "20p,Helvetica-Bold,white=1p", angle = 315)
(lat,lon) = line_read('tectonics/3PagodasFault.txt') # Three Pagodas Fault
fig.plot(x = lon, y = lat, pen = "1p,black,-")
fig.text(text = "TPF", x = 98.5, y = 14.5, font = "20p,Helvetica-Bold,white=1p", angle = 315)
(lat,lon) = line_read('tectonics/DBPF.txt') # Dien Bien Phu Fault
fig.plot(x = lon, y = lat, pen = "1p,black,-")
fig.text(text = "DBPF", x = 102, y = 19.5, font = "20p,Helvetica-Bold,white=1p", angle = 55)
(lat,lon) = line_read('tectonics/SongMaSuture.txt') # Song Ma Suture
fig.plot(x = lon, y = lat, pen = "1p,black,-")
fig.text(text = "Shan-Thai", x = 99, y = 20, font = "18p,Helvetica-Bold,black=0.5p,white", angle = 0)
fig.text(text = "Block", x = 99, y = 19.3, font = "18p,Helvetica-Bold,black=0.5p,white", angle = 0)
fig.text(text = "Indochina Block", x = 103.5, y = 15, font = "18p,Helvetica-Bold,black=0.5p,white", angle = 315)
fig.shift_origin(xshift= 1, yshift=-1.5)
fig.colorbar(frame = ["a%f"%(4000),"y+lElevation (m)"], position="+w4c/0.3c+h")
fig.shift_origin(xshift=-1, yshift=+1.5)
fig.shift_origin(xshift=0, yshift=-13)
# ------------------ Sub fig 2. earthquakes ------------------
region = "g"
projection = "E101/16/90/10c" # centerlon/centerlat/distnace_range/fig_size
frame = ["ya180"]
spacing = [0.1, 5]
fig.basemap(region=region, projection=projection, frame=frame)
fig.coast(region=region, projection=projection, frame=frame, water="white", land="gray", A=10000)
fig.plot(x=101.5, y=16.5, pen="1p,black,-", style="E-60d")
fig.plot(x=101.5, y=16.5, pen="1p,black,-", style="E-120d")
fig.plot(x=101.5, y=16.5, pen="1p,black,-", style="E-180d")
fig.text(x = [101.5, 101.5, 101.5], y = [-8.0, -38.0, -68], text = ['30', '60', '90'], font="13p")
fig.plot(x=[97,97,106,106,97], y=[11,21,21,11,11], pen="1p,red")
pygmt.makecpt(cmap="jet", series=[0, 100], background=True)
fig.plot(x = ev_lon, y = ev_lat, size = [0.4]*len(ev_lon), fill = ev_dep, style = "a", cmap = True, pen = "0.5p,white")
fig.shift_origin(xshift= 1, yshift=-1)
fig.colorbar(frame = ["a%f"%(50),"y+lFocal depth (km)"], position="+w4c/0.3c+h")
fig.shift_origin(xshift=-1, yshift=+1)
fig.shift_origin(xshift= 13, yshift= 13)
# ------------------ Sub fig 3. depth and vertical profile ------------------
region = [97,106,12,21]
projection = "B101.5/16.5/12/21/10c"
frame = ["xa2+lLongitude", "ya2+lLatitude", "nSWe"]
spacing = [0.1, 0.1]
depth_list = [100,200,300,400]
start_list = [ [97, 19], [97, 17.2], [101.8, 12] ]
end_list = [ [106, 15], [106, 13.2], [101.8, 21] ]
# depth profiles
for idepth, depth in enumerate(depth_list):
# read models
vel_init = init_model.interp_dep(depth, field='vel')
vel_inv = inv_model.interp_dep(depth, field='vel')
if idepth == 3:
fig.shift_origin(xshift=-39, yshift=-13)
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-2, 2], background=True)
x = vel_inv[:,0]; y = vel_inv[:,1]; value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2]*100
grid = pygmt.surface(x=x, y=y, z=value, spacing=spacing,region=region)
fig.grdimage(frame=frame,grid = grid,projection=projection, region=region) # nan_transparent may work
(lat,lon) = line_read('tectonics/Khorat_new.txt') # Khorat Plateau
fig.plot(x = lon, y = lat, pen = "1p,black")
# vertical profile location
fig.plot(x = [start_list[0][0],end_list[0][0]], y = [start_list[0][1],end_list[0][1],], pen = "2p,green,-")
fig.text(text = "A", x = start_list[0][0] + 0.5, y = start_list[0][1], font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.text(text = "A@+'@+", x = end_list[0][0] - 0.5, y = end_list[0][1] + 0.5, font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.plot(x = [start_list[1][0],end_list[1][0]], y = [start_list[1][1],end_list[1][1],], pen = "2p,green,-")
fig.text(text = "B", x = start_list[1][0] + 0.5, y = start_list[1][1], font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.text(text = "B@+'@+", x = end_list[1][0] - 0.5, y = end_list[1][1] + 0.5, font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.plot(x = [start_list[2][0],end_list[2][0]], y = [start_list[2][1],end_list[2][1],], pen = "2p,green,-")
fig.text(text = "C", x = start_list[2][0] - 0.5, y = start_list[2][1] + 0.5, font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.text(text = "C@+'@+", x = end_list[2][0] - 0.5, y = end_list[2][1] - 0.5, font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
# depth label
fig.text(text="%d km"%(depth), x = 98 , y = 12.5, font = "14p,Helvetica-Bold,black", fill = "white")
fig.shift_origin(xshift=13)
fig.shift_origin(yshift=6)
# vertical profiles
for iprof in range(len(start_list)):
# generate topography data
Npoints = 100
point_x = np.linspace(start_list[iprof][0],end_list[iprof][0],Npoints)
point_y = np.linspace(start_list[iprof][1],end_list[iprof][1],Npoints)
points = np.hstack((point_x.reshape(-1,1),point_y.reshape(-1,1)))
topo = np.array(pygmt.grdtrack(points=points, grid=grid_topo)[2])
topo_dis = [0]
for ip in range(1, Npoints):
dis = ffd.cal_dis(point_y[0], point_x[0], point_y[ip], point_x[ip])
topo_dis.append(dis)
topo_dis = np.array(topo_dis)
# read models
vel_init_sec = init_model.interp_sec(start_list[iprof], end_list[iprof], field='vel', val=10)
vel_inv_sec = inv_model.interp_sec(start_list[iprof], end_list[iprof], field='vel', val=10)
# plot topography
max_dis = np.max(vel_init_sec[:,2])
region = [0,max_dis,0,2000]
projection = "X%f/1c"%(max_dis/400*4)
frame = ["ya2000+lElevation (m)", "sW"]
fig.shift_origin(yshift=4)
fig.basemap(region=region, projection=projection, frame=frame)
fig.plot(x = topo_dis, y = topo, pen = "1p,black", frame = frame, projection = projection, region = region)
fig.shift_origin(yshift=-4)
# plot model
region = [0,max_dis,0,400]
projection = "X%f/-4c"%(max_dis/400*4)
frame = ["xa300+lDistance (km)", "ya100+lDepth (km)", "nSWe"]
spacing = [10, 5]
x_sec = vel_inv_sec[:,2]; y_sec = vel_inv_sec[:,3]; value_sec = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4]*100
grid = pygmt.surface(x=x_sec, y=y_sec, z=value_sec, spacing=spacing,region=region)
fig.grdimage(frame=frame,grid = grid,projection=projection, region=region) # nan_transparent may work
label_list = ['A', 'B', 'C']
fig.text(text = "%s"%(label_list[iprof]), x = 50, y = 50 , font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
fig.text(text = "%s@+'@+"%(label_list[iprof]), x = np.max(x) - 50, y = 50, font = "18p,Helvetica-Bold,black", fill = "lightblue", angle = 0)
if (iprof == 0):
fig.shift_origin(xshift=0, yshift=-6.5)
elif (iprof == 1):
fig.shift_origin(xshift=13, yshift=6.5)
fig.shift_origin(xshift= 2, yshift=-2.5)
fig.colorbar(frame = ["a%f"%(2),"y+ldlnVp (%)"], position="+w4c/0.3c+h")
fig.shift_origin(xshift=-2, yshift=+2.5)
fig.show()
fig.savefig("img/imaging_result.png")

View File

@@ -0,0 +1,45 @@
# %%
# download src_ref_files from Zenodo
import os
import requests
url = 'https://zenodo.org/records/14092478/files/src_rec_file.dat?download=1'
path = "1_src_rec_files/src_rec_file.dat"
# check file existence
if not os.path.exists(path):
try:
os.mkdir("1_src_rec_files")
except:
pass
print("Downloading src_rec_file.dat from Zenodo...")
response = requests.get(url, stream=True)
with open(path, 'wb') as out_file:
out_file.write(response.content)
print("Download complete.")
else:
print("src_rec_file.dat already exists.")
# %%
# download initial model from Zenodo
url = 'https://zenodo.org/records/14092478/files/model_init_N121_121_121.h5?download=1'
path = "2_models/model_init_N121_121_121.h5"
# check file existence
if not os.path.exists(path):
try:
os.mkdir("2_models")
except:
pass
print("Downloading model_init_N121_121_121.h5 from Zenodo...")
response = requests.get(url, stream=True)
with open(path, 'wb') as out_file:
out_file.write(response.content)
print("Download complete.")
else:
print("model_init_N121_121_121.h5 already exists.")

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Step 1: Generate necessary input files
python prepare_input_files.py
# Step 2: Run inversion
# # for WSL
# mpirun -n 8 --allow-run-as-root --oversubscribe ../../build/bin/TOMOATT -i 3_input_params/input_params_real.yaml
# for Linux
# mpirun -n 8 ../../build/bin/TOMOATT -i 3_input_params/input_params_real.yaml
# for conda install
mpirun -n 8 TOMOATT -i 3_input_params/input_params_real.yaml
# # Step 3 (Optional): Plot the results
# python plot_output.py

View File

@@ -0,0 +1,9 @@
97.716435 15.996933
97.909999 15.704275
98.075912 15.388543
98.283303 15.065462
98.504520 14.792299
98.753389 14.414982
99.306431 13.919170
99.569126 13.657715
99.831821 13.344572

View File

@@ -0,0 +1,12 @@
100.26019 17.132888
100.51411 17.490642
100.79624 17.903402
101.10658 18.261329
101.47335 18.591967
101.75549 19.004727
102.00940 19.362481
102.29154 19.802702
102.51724 20.242749
102.74295 20.627877
102.91223 21.122673
103.02508 21.919356

View File

@@ -0,0 +1,74 @@
101.3217 15.25436
101.3610 15.02633
101.4085 14.66495
101.6319 14.56644
101.6012 14.38869
101.4514 14.26901
101.7127 14.13520
101.9088 14.04399
102.1729 14.00737
102.4503 14.00100
102.7636 14.00578
103.0485 14.13474
103.3082 14.27712
103.5336 14.33471
103.7845 14.37077
103.9997 14.34649
104.2485 14.32079
104.4734 14.33280
104.6885 14.37674
104.9102 14.34013
105.1688 14.31806
105.3968 14.38630
105.5182 14.48660
105.5693 14.77796
105.8248 14.91528
106.1238 14.87758
106.3348 14.64013
106.4688 14.60983
106.7040 14.63849
106.9841 14.69472
107.1072 14.88782
106.9818 15.16007
106.8467 15.43551
106.7018 15.70776
106.4761 15.91474
106.7336 16.04609
106.9007 16.14401
106.9118 16.31668
106.7038 16.57524
106.4385 16.64211
106.2010 16.67623
106.0120 16.46044
105.8274 16.65030
105.8194 16.91355
105.5656 17.01331
105.2865 17.09928
104.9742 17.44792
104.8155 17.65625
104.6904 17.84917
104.4882 18.06029
104.2648 18.23726
104.2338 18.42014
104.0404 18.69778
103.8294 18.71916
103.6035 18.82287
103.4194 18.79012
103.1891 18.75828
102.9576 18.78853
102.7519 18.78060
102.4620 18.70688
102.2884 18.31131
102.3415 17.97336
102.3233 17.61750
102.3959 17.36994
102.5198 17.16424
102.4485 16.89594
102.2198 17.03361
102.0690 16.82544
101.9004 16.52085
101.7902 16.17219
101.5551 16.16099
101.3962 15.84821
101.3255 15.53741
101.3217 15.25436

View File

@@ -0,0 +1,7 @@
103.42006 21.261522
103.75862 21.015416
104.12539 20.687015
104.54859 20.386247
104.94357 20.140313
105.33856 19.811998
105.67712 19.565892

View File

@@ -0,0 +1,35 @@
97.160627 18.667449
97.439913 18.296889
97.702608 18.010759
97.979130 17.718541
98.283303 17.463175
98.550606 17.271720
98.765678 17.102918
99.057562 16.870374
99.306431 16.669104
99.555300 16.377656
99.831821 16.064504
100.03921 15.742171
100.21895 15.443462
100.39869 15.086120
100.56460 14.752446
100.78582 14.447648
100.96556 14.282677
101.60156 13.889472
101.90573 13.651846
102.20990 13.442356
102.51408 13.201059
102.80719 12.957404
103.10972 12.693070
103.48190 12.438190
103.78607 12.172426
104.09025 11.987404
104.36677 11.761654
104.62946 11.466553
104.91981 11.204539
105.18250 10.882527
105.43137 10.599681
105.72172 10.344518
106.01207 10.087398
106.30241 9.8312565
106.50981 9.6872272

View File

@@ -0,0 +1,105 @@
# %%
from pytomoatt.model import ATTModel
import os
import numpy as np
import h5py
# %% [markdown]
# # Step 1. Generate the ATT model based on the crust1.0 model.
# %%
# generate the .h5 model for TomoATT based on the crust1.0 model. Nearest extrapolation is used.
param_file = "./3_input_params/input_params_real.yaml"
am_crust1p0 = ATTModel(param_file)
am_crust1p0.grid_data_crust1(type="vp")
# %% [markdown]
# # Step 2. Generate the ATT model based on ak135 model.
# %%
# Step 2. Generate the ATT model based on ak135 model.
# ak135.h5 has a three-column dataset 'model'. First column: depth (in km), second column: Vp (in km/s), third column: Vs (in km/s).
# a text version of the ak135 model can be found in Kennett et al. (1995):
# Kennett, B. L., Engdahl, E. R., & Buland, R. (1995). Constraints on seismic velocities in the Earth from traveltimes. Geophysical Journal International, 122(1), 108-124.
# Load the 1D ak135 model from the .h5 file.
with h5py.File('ak135.h5', 'r') as f:
points_ak135 = f['model'][:]
am_ak135 = ATTModel(param_file)
# interpolate the 1D ak135 velocity model to the depths of the ATT model.
vel_1d = np.interp(am_ak135.depths, points_ak135[:,0], points_ak135[:,1], left=points_ak135[0,1], right=points_ak135[-1,1])
# Set the 3D velocity model by tiling the 1D velocity model along lat and lon directions.
am_ak135.vel = np.tile(vel_1d[:, None, None], (1, am_ak135.n_rtp[1], am_ak135.n_rtp[2]))
# %% [markdown]
# # Step 3. Combine ak135 model with crust1.0 model
# %%
# 1. set two depths
# if depth < depth_1, vel = crust1p0
# if depth_1 <= depth <= depth_2, vel = linear_interp between crust1p0 and ak135
# if depth > depth_2, vel = ak135
am_combined = ATTModel(param_file)
depth_1 = 35.0
depth_2 = 70.0
ratio = (am_ak135.depths - depth_1) / (depth_2 - depth_1)
ratio = np.clip(ratio, 0.0, 1.0)
ratio_3d = np.tile(ratio[:, None, None], (1, am_ak135.n_rtp[1], am_ak135.n_rtp[2]))
# linear interpolation
am_combined.vel = am_crust1p0.vel * (1 - ratio_3d) + am_ak135.vel * ratio_3d
# %% [markdown]
# # Step 4. post processing (OPTIONAL)
# %%
am_processed = am_combined.copy()
# 1. (OPTIONAL) monotonic increase check
# Ensure that the velocity model increases monotonically with depth.
am_processed.vel[::-1,:,:] = np.maximum.accumulate(am_processed.vel[::-1,:,:], axis=0)
# 2. (OPTIONAL) Gaussian smoothing to the combined model to avoid sharp discontinuities.
## Upgrade PyTomoATT to version 0.2.10 or later to use this function.
am_processed.smooth(sigma=am_processed.d_rtp, unit_deg=True, mode='nearest') # standard deviation for Gaussian kernel along each axis (ddep, dlat, dlon)
# %%
# output as .h5 file
n_rtp = am_processed.n_rtp
fname = f"constant_velocity_N{n_rtp[0]:d}_{n_rtp[1]:d}_{n_rtp[2]:d}_PyTomoATT.h5"
am_processed.write(fname)
# %%
# visualization of the central lat-lon slice
import matplotlib.pyplot as plt
dep = am_processed.depths
vel = am_processed.vel[:, am_processed.n_rtp[1]//2, am_processed.n_rtp[2]//2]
lat = am_processed.latitudes[am_processed.n_rtp[1]//2]
lon = am_processed.longitudes[am_processed.n_rtp[2]//2]
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(1,1,1)
ax.plot(vel, dep, label='Velocity', color='blue')
ax.invert_yaxis()
ax.set_xlabel('Vp (km/s)', fontsize=16)
ax.set_ylabel('Depth (km)', fontsize=16)
ax.tick_params(axis='x', labelsize=16)
ax.tick_params(axis='y', labelsize=16)
ax.set_title(f'Velocity Profile at Lat: {lat:.2f}, Lon: {lon:.2f}', fontsize=16)
ax.grid()
ax.legend(fontsize=16)
plt.show()
os.makedirs("figs", exist_ok=True)
fig.savefig("figs/velocity_profile_lat%.2f_lon%.2f.png"%(lat, lon), facecolor='white', edgecolor='white', bbox_inches='tight')

View File

@@ -0,0 +1,186 @@
version: 3
#################################################
# computational domain #
#################################################
domain:
min_max_dep: [-50, 550] # depth in km
min_max_lat: [10.5, 22.5] # latitude in degree
min_max_lon: [95.5, 107.5] # longitude in degree
n_rtp: [121, 121, 121] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_file.dat # source receiver file path
swap_src_rec: false # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_init_N121_121_121.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultaneous runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_real # path to output directory (default is ./OUTPUT_FILES/)
output_source_field: false # True: output the traveltime field and adjoint field of all sources at each iteration. Default: false. File: 'out_data_sim_group_X'.
output_kernel: false
output_final_model: true # True: output merged final model. This file can be used as the input model for TomoATT. Default: true. File: 'model_final.h5'.
output_middle_model: false # True: output merged intermediate models during inversion. This file can be used as the input model for TomoATT. Default: false. File: 'middle_model_step_XXXX.h5'
output_in_process: false # True: output at each inv iteration, otherwise, only output step 0, Niter-1, Niter. Default: true. File: 'out_data_sim_group_0'.
output_in_process_data: false # True: output src_rec_file at each inv iteration, otherwise, only output step 0, Niter-2, Niter-1. Default: true. File: 'src_rec_file_step_XXXX.dat'
single_precision_output: false # True: output results in single precision. Default: false.
verbose_output_level: 0 # output internal parameters, (to do)
output_file_format: 0 # 0: hdf5, 1: ascii
# output files:
# File: 'out_data_grid.h5'. Keys: ['Mesh']['elem_conn'], element index;
# ['Mesh']['node_coords_p'], phi coordinates of nodes;
# ['Mesh']['node_coords_t'], theta coordinates of nodes;
# ['Mesh']['node_coords_r'], r coordinates of nodes;
# ['Mesh']['node_coords_x'], phi coordinates of elements;
# ['Mesh']['node_coords_y'], theta coordinates of elements;
# ['Mesh']['node_coords_z'], r coordinates of elements;
# File: 'out_data_sim_group_0'. Keys: ['model']['vel_inv_XXXX'], velocity model at iteration XXXX;
# ['model']['xi_inv_XXXX'], xi model at iteration XXXX;
# ['model']['eta_inv_XXXX'], eta model at iteration XXXX
# ['model']['Ks_inv_XXXX'], sensitivity kernel related to slowness at iteration XXXX
# ['model']['Kxi_inv_XXXX'], sensitivity kernel related to xi at iteration XXXX
# ['model']['Keta_inv_XXXX'], sensitivity kernel related to eta at iteration XXXX
# ['model']['Ks_density_inv_XXXX'], kernel density of Ks at iteration XXXX
# ['model']['Kxi_density_inv_XXXX'], kernel density of Kxi at iteration XXXX
# ['model']['Keta_density_inv_XXXX'], kernel density of Keta at iteration XXXX
# ['model']['Ks_over_Kden_inv_XXXX'], slowness kernel over kernel density at iteration XXXX
# ['model']['Kxi_over_Kden_inv_XXXX'], xi kernel over kernel density at iteration XXXX
# ['model']['Keta_over_Kden_inv_XXXX'], eta kernel over kernel density at iteration XXXX
# ['model']['Ks_update_inv_XXXX'], slowness kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Kxi_update_inv_XXXX'], xi kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['model']['Keta_update_inv_XXXX'], eta kernel over kernel density at iteration XXXX, smoothed by inversion grid
# ['1dinv']['vel_1dinv_inv_XXXX'], 2d velocity model at iteration XXXX, in 1d inversion mode
# ['1dinv']['r_1dinv'], r coordinates (depth), in 1d inversion mode
# ['1dinv']['t_1dinv'], t coordinates (epicenter distance), in 1d inversion mode
# File: 'src_rec_file_step_XXXX.dat' or 'src_rec_file_forward.dat'. The synthetic traveltime data file.
# File: 'final_model.h5'. Keys: ['eta'], ['xi'], ['vel'], the final model.
# File: 'middle_model_step_XXXX.h5'. Keys: ['eta'], ['xi'], ['vel'], the model at step XXXX.
# File: 'inversion_grid.txt'. The location of inversion grid nodes
# File: 'objective_function.txt'. The objective function value at each iteration
# File: 'out_data_sim_group_X'. Keys: ['src_YYYY']['time_field_inv_XXXX'], traveltime field of source YYYY at iteration XXXX;
# ['src_YYYY']['adjoint_field_inv_XXXX'], adjoint field of source YYYY at iteration XXXX;
# ['1dinv']['time_field_1dinv_YYYY_inv_XXXX'], 2d traveltime field of source YYYY at iteration XXXX, in 1d inversion mode
# ['1dinv']['adjoint_field_1dinv_YYYY_inv_XXXX'], 2d adjoint field of source YYYY at iteration XXXX, in 1d inversion mode
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
# 4 for 1d model inversion
run_mode: 1
have_tele_data: true # An error will be reported if false but source out of study region is used. Default: false.
###################################################
# model update parameters setting #
###################################################
model_update:
max_iterations: 80 # maximum number of inversion iterations
step_length: 0.01 # the initial step length of model perturbation. 0.01 means maximum 1% perturbation for each iteration.
# parameters for optim_method 0 (gradient_descent)
optim_method_0:
# if step_method:1. if the angle between the current and the previous gradients is greater than step_length_gradient_angle, step size -> step length * step_length_change[0].
# otherwise, step size -> step length * step_length_change[1].
step_length_gradient_angle: 120 # default: 120.0
step_length_change: [0.5, 1.41] # default: [0.5,1.2]
Kdensity_coe: 0.3 # default: 0.0, range: 0.0 - 1.0
# parameters for smooth method 0 (multigrid model parametrization)
# inversion grid can be viewed in OUTPUT_FILES/inversion_grid.txt
n_inversion_grid: 5 # number of inversion grid sets
uniform_inv_grid_dep: false # true if use uniform inversion grid for dep, false if use flexible inversion grid
uniform_inv_grid_lat: false # true if use uniform inversion grid for lat, false if use flexible inversion grid
uniform_inv_grid_lon: false # true if use uniform inversion grid for lon, false if use flexible inversion grid
# settings for flexible inversion grid
dep_inv: [-50, -25, 0, 50, 100, 150, 200, 275, 350, 425, 500, 600,700] # inversion grid for vel in depth (km)
lat_inv: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] # inversion grid for vel in latitude (degree)
lon_inv: [95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108] # inversion grid for vel in longitude (degree)
trapezoid: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# if we want to use another inversion grid for inverting anisotropy, set invgrid_ani: true (default: false)
invgrid_ani: false
# ---------- flexible inversion grid setting for anisotropy ----------
# settings for flexible inversion grid for anisotropy
dep_inv_ani: [-5, -2, 0, 3, 7, 12, 17, 23, 30, 38, 47, 57] # inversion grid for ani in depth (km)
lat_inv_ani: [-2.8, -2.3, -1.8, -1.3, -0.8, -0.3, 0.2, 0.7, 1.2, 1.7, 2.2, 2.7] # inversion grid for ani in latitude (degree)
lon_inv_ani: [-1.2, -0.9, -0.6, -0.3, 0, 0.3, 0.6, 0.9, 1.2] # inversion grid for ani in longitude (degree)
trapezoid_ani: [1, 0, 50] # usually set as [1.0, 0.0, 50.0] (default)
# Carefully change trapezoid and trapezoid_ani, if you really want to use trapezoid inversion grid, increasing the inversion grid spacing with depth to account for the worse data coverage in greater depths.
# The trapezoid_ inversion grid with index (i,j,k) in longitude, latitude, and depth is defined as:
# if dep_inv[k] < trapezoid[1], lon = lon_inv[i];
# lat = lat_inv[j];
# dep = dep_inv[k];
# if trapezoid[1] <= dep_inv[k] < trapezoid[2], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*(dep_inv[k]-trapezoid[1])/(trapezoid[2]-trapezoid[1])*trapezoid[0];
# dep = dep_inv[k];
# if trapezoid[2] <= dep_inv[k], lon = mid_lon_inv+(lon_inv[i]-mid_lon_inv)*trapezoid[0];
# lat = mid_lat_inv+(lat_inv[i]-mid_lat_inv)*trapezoid[0];
# dep = dep_inv[k];
# The shape of trapezoid inversion gird (x) looks like:
#
# lon_inv[0] [1] [2] [3] [4]
# |<-------- (lon_inv[end] - lon_inv[0]) ---->|
# dep_inv[0] | x x x x x |
# | |
# dep_inv[1] | x x x x x |
# | |
# dep_inv[2] = trapezoid[1] / x x x x x \
# / \
# dep_inv[3] / x x x x x \
# / \
# dep_inv[4] = trapezoid[2] / x x x x x \
# | |
# dep_inv[5] | x x x x x |
# | |
# dep_inv[6] | x x x x x |
# |<---- trapezoid[0]* (lon_inv[end] - lon_inv[0]) ------>|
# -------------- using absolute traveltime data --------------
abs_time:
use_abs_time: false # 'true' for using absolute traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common source differential traveltime data --------------
cs_dif_time:
use_cs_time: true # 'true' for using common source differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- using common receiver differential traveltime data --------------
cr_dif_time:
use_cr_time: false # 'true' for using common receiver differential traveltime data to update model parameters; 'false' for not using (no need to set parameters in this section)
# -------------- inversion parameters --------------
update_slowness : true # update slowness (velocity) or not. default: true
update_azi_ani : false # update azimuthal anisotropy (xi, eta) or not. default: false
use_sta_correction: true
# initial_sta_correction_file: 4_initial_station_correct/station_correction_file_step_0010.dat # the path of initial station correction
step_length_sta_correction: 0.01 # step length relate to the update of station correction terms

Binary file not shown.

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# run the script to generate HDF5 model files based on community models
# 1. crust1.0 (Laske et al., 2013) + ak135 model (Kennett et al., 1995)
python 1_crust1.0_ak135_model.py
# References:
# Laske, G., Masters, G., Ma, Z., & Pasyanos, M. (2013, April). Update on CRUST1. 0—A 1-degree global model of Earths crust. In Geophysical research abstracts (Vol. 15, No. 15, p. 2658).
# Kennett, B. L., Engdahl, E. R., & Buland, R. (1995). Constraints on seismic velocities in the Earth from traveltimes. Geophysical Journal International, 122(1), 108-124.

View File

@@ -0,0 +1,287 @@
# %%
from pytomoatt.model import ATTModel
from pytomoatt.checkerboard import Checker
import os
import numpy as np
import h5py
# %% [markdown]
# # read YAML parameter file to obtain the grid parameters for the model
# %%
output_path = "models"
os.makedirs(output_path, exist_ok=True)
par_file = "input_params/input_params.yaml"
att_model = ATTModel(par_file)
n_rtp = att_model.n_rtp # grid node numbers in r (depth), t (longtitude), p (latitude) directions
am_depths = att_model.depths # depths in km
am_latitudes = att_model.latitudes # latitudes in degrees
am_longitudes = att_model.longitudes # longitudes in degrees
print("grid node numbers (N_r, N_t, N_p):", n_rtp)
print("depths (km):", am_depths)
print("latitudes (degree):", am_latitudes)
print("longitudes (degree):", am_longitudes)
# %% [markdown]
# # eg1. generate model with constant velocity
# %%
# case 1. ---------- generate a constant velocity model using PyTomoATT module -------------
# set the velocity model to a constant value
constant_v = 6.0 # constant velocity (km/s)
att_model.vel[:,:,:] = constant_v
att_model.xi[:,:,:] = 0.0
att_model.eta[:,:,:] = 0.0
# write the model to a file
fname = "%s/constant_velocity_N%d_%d_%d_PyTomoATT.h5"%(output_path, n_rtp[0], n_rtp[1], n_rtp[2])
att_model.write(fname)
print("generate model using PyTomoATT:", fname)
# case 2. ---------- generate a constant velocity model using plain loop (h5py module is required) -------------
# set the velocity model to a constant value
vel = np.zeros(n_rtp)
xi = np.zeros(n_rtp)
eta = np.zeros(n_rtp)
for ir in range(n_rtp[0]):
for it in range(n_rtp[1]):
for ip in range(n_rtp[2]):
vel[ir, it, ip] = constant_v
fname = "%s/constant_velocity_N%d_%d_%d_loop.h5"%(output_path, n_rtp[0], n_rtp[1], n_rtp[2])
with h5py.File(fname, 'w') as f:
f.create_dataset('vel', data=vel)
f.create_dataset('xi', data=xi)
f.create_dataset('eta', data=eta)
print("generate model using plain loop:", fname)
# %% [markdown]
# # eg2. generate a linear velocity model:
# vel = 5.0, if depth < 0 km
#
# vel = 5.0 + 0.1 * depth, if 0 km <= depth <= 30 km
#
# vel = 8.0, if depth > 30 km
# %%
# case 1. ---------- generate a constant velocity model using PyTomoATT module -------------
# set the velocity model to a constant value
idx = np.where((am_depths >= 0.0) & (am_depths <= 30.0))
depth = am_depths[idx]
att_model.vel[idx,:,:] = 5.0 + 0.1 * depth[:, np.newaxis, np.newaxis] # velocity increases linearly from 5.0 to 8.0 km/s
att_model.vel[np.where(am_depths > 30.0),:,:] = 8.0 # velocity is constant at 8.0 km/s below 30.0 km depth
att_model.vel[np.where(am_depths < 0.0),:,:] = 5.0 # velocity is constant at 5.0 km/s above 0.0 km depth
att_model.xi[:,:,:] = 0.0
att_model.eta[:,:,:] = 0.0
# write the model to a file
fname = "%s/linear_velocity_N%d_%d_%d_PyTomoATT.h5"%(output_path, n_rtp[0], n_rtp[1], n_rtp[2])
att_model.write(fname)
print("generate model using PyTomoATT:", fname)
# case 2. ---------- generate a linear velocity model using plain loop (h5py module is required) -------------
# set the velocity model to a linear value
vel = np.zeros(n_rtp)
xi = np.zeros(n_rtp)
eta = np.zeros(n_rtp)
for ir in range(n_rtp[0]):
for it in range(n_rtp[1]):
for ip in range(n_rtp[2]):
if am_depths[ir] < 0.0:
vel[ir, it, ip] = 5.0
elif am_depths[ir] <= 30.0:
vel[ir, it, ip] = 5.0 + 0.1 * am_depths[ir]
else:
vel[ir, it, ip] = 8.0
fname = "%s/linear_velocity_N%d_%d_%d_loop.h5"%(output_path, n_rtp[0], n_rtp[1], n_rtp[2])
with h5py.File(fname, 'w') as f:
f.create_dataset('vel', data=vel)
f.create_dataset('xi', data=xi)
f.create_dataset('eta', data=eta)
print("generate model using plain loop:", fname)
# %% [markdown]
# # eg3. generate checkerboard model for velocity and anisotropy.
#
# assign perturbation
# %%
# case 1. ---------- generate a constant velocity model using PyTomoATT module -------------
# file name of the background model
bg_model_fname = "%s/linear_velocity_N%d_%d_%d_PyTomoATT.h5" % (output_path, n_rtp[0], n_rtp[1], n_rtp[2])
lim_x = [0.5, 1.5] # longitude limits of the checkerboard
lim_y = [0.25, 0.75] # latitude limits of the checkerboard
lim_z = [0, 30] # depth limits of the checkerboard
pert_vel = 0.1 # amplitude of velocity perturbation (%)
pert_ani = 0.05 # amplitude of anisotropy perturbation (fraction)
ani_dir = 60.0 # fast velocity direction (anti-clockwise from x-axis, in degrees)
n_pert_x = 4 # number of checkers in x (lon) direction
n_pert_y = 2 # number of checkers in y (lat) direction
n_pert_z = 3 # number of checkers in z (dep) direction
size_x = (lim_x[1] - lim_x[0]) / n_pert_x # size of each checker in x direction
size_y = (lim_y[1] - lim_y[0]) / n_pert_y # size of each checker in y direction
size_z = (lim_z[1] - lim_z[0]) / n_pert_z # size of each checker in z direction
ckb = Checker(bg_model_fname, para_fname=par_file)
# n_pert_x, n_pert_y, n_pert_z: number of checkers in x (lon), y (lat), z (dep) directions
# pert_vel: amplitude of velocity perturbation (km/s)
# pert_ani: amplitude of anisotropy perturbation (fraction)
# ani_dir: fast velicty direction (anti-cloclkwise from x-axis, in degrees)
# lim_x, lim_y, lim_z: limits of the checkerboard in x (lon), y (lat), z (dep) directions
ckb.checkerboard(
n_pert_x=n_pert_x, n_pert_y=n_pert_y, n_pert_z=n_pert_z,
pert_vel=pert_vel, pert_ani=pert_ani, ani_dir=ani_dir,
lim_x=lim_x, lim_y=lim_y, lim_z=lim_z
)
fname = "%s/linear_velocity_ckb_N%d_%d_%d_PyTomoATT.h5" % (output_path, n_rtp[0], n_rtp[1], n_rtp[2])
ckb.write(fname)
print("generate checkerboard model based on the linear velocity model using PyTomoATT:", fname)
# case 2. ---------- generate a checkerboard model using plain loop (h5py module is required) -------------
# read the background model
bg_model = np.zeros(n_rtp)
with h5py.File(bg_model_fname, 'r') as f:
bg_model = f['vel'][:]
# set the checkerboard model
vel = np.zeros(n_rtp)
xi = np.zeros(n_rtp)
eta = np.zeros(n_rtp)
for ir in range(n_rtp[0]):
for it in range(n_rtp[1]):
for ip in range(n_rtp[2]):
depth = am_depths[ir]
lat = am_latitudes[it]
lon = am_longitudes[ip]
# check if the current grid node is within the checkerboard limits
if (lim_x[0] <= lon <= lim_x[1]) and (lim_y[0] <= lat <= lim_y[1]) and (lim_z[0] <= depth <= lim_z[1]):
sigma_vel = np.sin(np.pi * (lon - lim_x[0])/size_x) * np.sin(np.pi * (lat - lim_y[0])/size_y) * np.sin(np.pi * (depth - lim_z[0])/size_z)
sigma_ani = np.sin(np.pi * (lon - lim_x[0])/size_x) * np.sin(np.pi * (lat - lim_y[0])/size_y) * np.sin(np.pi * (depth - lim_z[0])/size_z)
if (sigma_ani > 0):
psi = ani_dir / 180.0 * np.pi # convert degrees to radians
elif (sigma_ani < 0):
psi = (ani_dir + 90.0) / 180.0 * np.pi
else:
psi = 0.0
else:
sigma_vel = 0.0
sigma_ani = 0.0
psi = 0.0
# set the velocity and anisotropy
vel[ir, it, ip] = bg_model[ir, it, ip] * (1.0 + pert_vel * sigma_vel)
xi[ir, it, ip] = pert_ani * abs(sigma_ani) * np.cos(2*psi)
eta[ir, it, ip] = pert_ani * abs(sigma_ani) * np.sin(2*psi)
# write the model to a file
fname = "%s/linear_velocity_ckb_N%d_%d_%d_loop.h5" % (output_path, n_rtp[0], n_rtp[1], n_rtp[2])
with h5py.File(fname, 'w') as f:
f.create_dataset('vel', data=vel)
f.create_dataset('xi', data=xi)
f.create_dataset('eta', data=eta)
print("generate checkerboard model based on the linear velocity model using plain loop:", fname)
# %% [markdown]
# # eg4. generate flexible checkerboard model
#
# the checker size increases with depth;
#
# the checker size is large for anisotropy;
# %%
# only
# file name of the background model
bg_model_fname = "%s/linear_velocity_N%d_%d_%d_PyTomoATT.h5" % (output_path, n_rtp[0], n_rtp[1], n_rtp[2])
# read the background model
bg_model = np.zeros(n_rtp)
with h5py.File(bg_model_fname, 'r') as f:
bg_model = f['vel'][:]
# set the checkerboard model
vel = np.zeros(n_rtp)
xi = np.zeros(n_rtp)
eta = np.zeros(n_rtp)
for ir in range(n_rtp[0]):
for it in range(n_rtp[1]):
for ip in range(n_rtp[2]):
depth = am_depths[ir]
lat = am_latitudes[it]
lon = am_longitudes[ip]
if ((depth >= 0.0) and (depth <= 8.0)):
size_vel = 0.2
size_ani = 0.3
sigma_vel = np.sin(np.pi * lon/size_vel) * np.sin(np.pi * lat/size_vel) * np.sin(np.pi * depth/8.0)
sigma_ani = np.sin(np.pi * lon/size_ani) * np.sin(np.pi * lat/size_ani) * np.sin(np.pi * depth/8.0)
elif ((depth > 8.0) and (depth <= 20.0)):
size_vel = 0.3
size_ani = 0.4
sigma_vel = np.sin(np.pi * lon/size_vel) * np.sin(np.pi * lat/size_vel) * np.sin(np.pi * (depth - 8.0)/12.0 + np.pi)
sigma_ani = np.sin(np.pi * lon/size_ani) * np.sin(np.pi * lat/size_ani) * np.sin(np.pi * (depth - 8.0)/12.0 + np.pi)
elif ((depth > 20.0) and (depth <= 36.0)):
size_vel = 0.4
size_ani = 0.5
sigma_vel = np.sin(np.pi * lon/size_vel) * np.sin(np.pi * lat/size_vel) * np.sin(np.pi * (depth - 20.0)/16.0 + 2*np.pi)
sigma_ani = np.sin(np.pi * lon/size_ani) * np.sin(np.pi * lat/size_ani) * np.sin(np.pi * (depth - 20.0)/16.0 + 2*np.pi)
else:
sigma_vel = 0.0
sigma_ani = 0.0
if (sigma_ani > 0):
psi = ani_dir / 180.0 * np.pi # convert degrees to radians
elif (sigma_ani < 0):
psi = (ani_dir + 90.0) / 180.0 * np.pi
else:
psi = 0.0
# set the velocity and anisotropy
vel[ir, it, ip] = bg_model[ir, it, ip] * (1.0 + pert_vel * sigma_vel)
xi[ir, it, ip] = pert_ani * abs(sigma_ani) * np.cos(2*psi)
eta[ir, it, ip] = pert_ani * abs(sigma_ani) * np.sin(2*psi)
# write the model to a file
fname = "%s/linear_velocity_ckb_flex_N%d_%d_%d.h5" % (output_path, n_rtp[0], n_rtp[1], n_rtp[2])
with h5py.File(fname, 'w') as f:
f.create_dataset('vel', data=vel)
f.create_dataset('xi', data=xi)
f.create_dataset('eta', data=eta)
print("generate flexible checkerboard model based on the linear velocity model using plain loop:", fname)

View File

@@ -0,0 +1,338 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
import os
output_path = "figs"
os.makedirs(output_path, exist_ok=True)
# %% [markdown]
# # eg1. plot constant velocity model
# %%
# ---------------- read model files ----------------
# file names
# init_model_file = 'models/constant_velocity_N61_51_101_PyTomoATT.h5' # initial model file
init_model_file = 'models/constant_velocity_N61_51_101_loop.h5' # initial model file
par_file = 'input_params/input_params.yaml' # parameter file
# read initial and final model file
att_model = ATTModel.read(init_model_file, par_file)
init_model = att_model.to_xarray()
# interp vel at depth = 20 km
depth = 20.0
vel_init = init_model.interp_dep(depth, field='vel') # vel_init[i,:] are (lon, lat, vel)
# ----------------- pygmt plot ------------------
fig = pygmt.Figure()
pygmt.makecpt(cmap="seis", series=[5, 7], background=True, reverse=False) # colorbar
# ------------ plot horizontal profile of velocity ------------
region = [0, 2, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa1","ya1","+tVelocity (km/s)"], projection="M10c") # base map
depth = 20.0
prof_init = init_model.interp_dep(depth, field='vel') # prof_init[i,:] are (lon, lat, vel)
lon = prof_init[:,0] # longitude
lat = prof_init[:,1] # latitude
vel = prof_init[:,2] # velocity
grid = pygmt.surface(x=lon, y=lat, z=vel, spacing=0.04,region=region)
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 = ["a1","y+lVp (km/s)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=0, yshift= 1.5)
# ------------ plot horivertical profile of velocity ------------
fig.shift_origin(xshift=11, yshift= 0)
region = [0, 40, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa20+lDepth (km)","ya1+lLatitude","nSwE"], projection="X3c/5c") # base map
start = [1,0]; end = [1,1]; gap = 1
prof_init = init_model.interp_sec(start, end, field='vel', val = gap) # prof_init[i,:] are (lon, lat, dis, dep, vel)
lat = prof_init[:,1] # lat
dep = prof_init[:,3] # depth
vel = prof_init[:,4] # velocity
grid = pygmt.surface(x=dep, y=lat, z=vel, spacing="1/0.04",region=region)
fig.grdimage(grid = grid) # plot figure
fig.savefig("figs/constant_velocity.png") # save figure
fig.show()
# %% [markdown]
# # eg2. plot linear velocity model
# %%
# ---------------- read model files ----------------
# file names
# init_model_file = 'models/linear_velocity_N61_51_101_PyTomoATT.h5' # initial model file
init_model_file = 'models/linear_velocity_N61_51_101_loop.h5' # initial model file
par_file = 'input_params/input_params.yaml' # parameter file
# read initial and final model file
att_model = ATTModel.read(init_model_file, par_file)
init_model = att_model.to_xarray()
# # interp vel at depth = 20 km
# depth = 20.0
# vel_init = init_model.interp_dep(depth, field='vel') # vel_init[i,:] are (lon, lat, vel)
# ----------------- pygmt plot ------------------
fig = pygmt.Figure()
pygmt.makecpt(cmap="seis", series=[5, 8], background=True, reverse=False) # colorbar
# ------------ plot horizontal profile of velocity ------------
region = [0, 2, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa1","ya1","+tVelocity (km/s)"], projection="M10c") # base map
depth = 20.0
prof_init = init_model.interp_dep(depth, field='vel') # prof_init[i,:] are (lon, lat, vel)
lon = prof_init[:,0] # longitude
lat = prof_init[:,1] # latitude
vel = prof_init[:,2] # velocity
grid = pygmt.surface(x=lon, y=lat, z=vel, spacing=0.04,region=region)
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 = ["a1","y+lVp (km/s)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=0, yshift= 1.5)
# ------------ plot horivertical profile of velocity ------------
fig.shift_origin(xshift=11, yshift= 0)
region = [0, 40, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa20+lDepth (km)","ya1+lLatitude","nSwE"], projection="X3c/5c") # base map
start = [1,0]; end = [1,1]; gap = 1
prof_init = init_model.interp_sec(start, end, field='vel', val = gap) # prof_init[i,:] are (lon, lat, dis, dep, vel)
lat = prof_init[:,1] # lat
dep = prof_init[:,3] # depth
vel = prof_init[:,4] # velocity
grid = pygmt.surface(x=dep, y=lat, z=vel, spacing="1/0.04",region=region)
fig.grdimage(grid = grid) # plot figure
fig.savefig("figs/linear_velocity.png") # save figure
fig.show()
# %% [markdown]
# # eg3. plot checkerboard model
# %%
# ---------------- read model files ----------------
# file names
init_model_file = 'models/linear_velocity_N61_51_101_PyTomoATT.h5' # initial model file
ckb_model_file = 'models/linear_velocity_ckb_N61_51_101_PyTomoATT.h5' # checkerboard model file
# ckb_model_file = 'models/linear_velocity_ckb_N61_51_101_loop.h5' # checkerboard model file
par_file = 'input_params/input_params.yaml' # parameter file
# read initial and final model file
att_model = ATTModel.read(init_model_file, par_file)
init_model = att_model.to_xarray()
att_model = ATTModel.read(ckb_model_file, par_file)
ckb_model = att_model.to_xarray()
# # interp vel at depth = 20 km
# depth = 20.0
# vel_init = init_model.interp_dep(depth, field='vel') # vel_init[i,:] are (lon, lat, vel)
# vel_ckb = ckb_model.interp_dep(depth, field='vel') # vel_ckb[i,:] are (lon, lat, vel)
# ----------------- pygmt plot ------------------
fig = pygmt.Figure()
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-10,10], background=True, reverse=False) # colorbar
# ------------ plot horizontal profile of velocity ------------
region = [0, 2, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa1","ya1","+tVelocity perturbation (%)"], projection="M10c") # base map
# velocity perturbation at depth = 15 km
depth = 15.0
prof_init = init_model.interp_dep(depth, field='vel') # prof_init[i,:] are (lon, lat, vel)
prof_ckb = ckb_model.interp_dep(depth, field='vel') # prof_ckb[i,:] are (lon, lat, vel)
lon = prof_init[:,0] # longitude
lat = prof_init[:,1] # latitude
vel_pert = (prof_ckb[:,2] - prof_init[:,2])/prof_init[:,2] * 100 # velocity perturbation related to initial model
grid = pygmt.surface(x=lon, y=lat, z=vel_pert, spacing=0.01,region=region)
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")
# fast velocity directions (FVDs)
samp_interval = 3 # control the density of anisotropic arrows
width = 0.06 # width of the anisotropic arrow
ani_per_1 = 0.01; ani_per_2 = 0.05; scale = 0.5; basic = 0.1 # control the length of anisotropic arrows related to the amplitude of anisotropy. length = 0.1 + (amplitude - ani_per_1) / (ani_per_2 - ani_per_1) * scale
ani_thd = ani_per_1 # if the amplitude of anisotropy is smaller than ani_thd, no anisotropic arrow will be plotted
phi = ckb_model.interp_dep(depth, field='phi', samp_interval=samp_interval) # phi_inv[i,:] are (lon, lat, phi)
epsilon = ckb_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval) # epsilon_inv[i,:] are (lon, lat, epsilon)
ani_lon = phi[:,0].reshape(-1,1)
ani_lat = phi[:,1].reshape(-1,1)
ani_phi = phi[:,2].reshape(-1,1)
length = ((epsilon[:,2] - ani_per_1) / (ani_per_2 - ani_per_1) * scale + basic).reshape(-1,1)
ani_arrow = np.hstack([ani_lon, ani_lat, ani_phi, length, np.ones((ani_lon.size,1))*width]) # lon, lat, color, angle[-90,90], length, width
# remove arrows with small amplitude of anisotropy
idx = np.where(epsilon[:,2] > ani_thd)[0] # indices of arrows with large enough amplitude of anisotropy
ani_arrow = ani_arrow[idx,:] # remove arrows with small amplitude of anisotropy
# plot anisotropic arrows
fig.plot(ani_arrow, style='j', fill='yellow1', pen='0.5p,black') # plot fast velocity direction
# colorbar
fig.shift_origin(xshift=0, yshift=-1.5)
fig.colorbar(frame = ["a10","y+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=0, yshift= 1.5)
# ------------ plot horivertical profile of velocity ------------
fig.shift_origin(xshift=11, yshift= 0)
region = [0, 40, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa20+lDepth (km)","ya1+lLatitude","nSwE"], projection="X3c/5c") # base map
start = [0.875,0]; end = [0.875,1]; gap = 1
prof_init = init_model.interp_sec(start, end, field='vel', val = gap) # prof_init[i,:] are (lon, lat, dis, dep, vel)
prof_ckb = ckb_model.interp_sec(start, end, field='vel', val = gap) # prof_ckb[i,:] are (lon, lat, dis, dep, vel)
lat = prof_init[:,1] # lat
dep = prof_init[:,3] # depth
vel = (prof_ckb[:,4] - prof_init[:,4])/prof_init[:,4] * 100 # velocity perturbation related to initial model
grid = pygmt.surface(x=dep, y=lat, z=vel, spacing="1/0.01",region=region)
fig.grdimage(grid = grid) # plot figure
fig.savefig("figs/checkerboard_velocity.png") # save figure
fig.show()
# %% [markdown]
# # eg4. plot flexible checkerboard model
# %%
# ---------------- read model files ----------------
# file names
init_model_file = 'models/linear_velocity_N61_51_101_PyTomoATT.h5' # initial model file
ckb_model_file = 'models/linear_velocity_ckb_flex_N61_51_101.h5' # checkerboard model file
par_file = 'input_params/input_params.yaml' # parameter file
# read initial and final model file
att_model = ATTModel.read(init_model_file, par_file)
init_model = att_model.to_xarray()
att_model = ATTModel.read(ckb_model_file, par_file)
ckb_model = att_model.to_xarray()
# # interp vel at depth = 20 km
# depth = 20.0
# vel_init = init_model.interp_dep(depth, field='vel') # vel_init[i,:] are (lon, lat, vel)
# vel_ckb = ckb_model.interp_dep(depth, field='vel') # vel_ckb[i,:] are (lon, lat, vel)
# ----------------- pygmt plot ------------------
fig = pygmt.Figure()
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-10,10], background=True, reverse=False) # colorbar
for depth in [4,14,28]:
# ------------ plot horizontal profile of velocity ------------
region = [0, 2, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa1","ya1","NsEw"], projection="M10c") # base map
# velocity perturbation at depth = 15 km
prof_init = init_model.interp_dep(depth, field='vel') # prof_init[i,:] are (lon, lat, vel)
prof_ckb = ckb_model.interp_dep(depth, field='vel') # prof_ckb[i,:] are (lon, lat, vel)
lon = prof_init[:,0] # longitude
lat = prof_init[:,1] # latitude
vel_pert = (prof_ckb[:,2] - prof_init[:,2])/prof_init[:,2] * 100 # velocity perturbation related to initial model
grid = pygmt.surface(x=lon, y=lat, z=vel_pert, spacing=0.01,region=region)
fig.grdimage(grid = grid) # plot figure
# fast velocity directions (FVDs)
samp_interval = 3 # control the density of anisotropic arrows
width = 0.06 # width of the anisotropic arrow
ani_per_1 = 0.01; ani_per_2 = 0.05; scale = 0.5; basic = 0.1 # control the length of anisotropic arrows related to the amplitude of anisotropy. length = 0.1 + (amplitude - ani_per_1) / (ani_per_2 - ani_per_1) * scale
ani_thd = ani_per_1 # if the amplitude of anisotropy is smaller than ani_thd, no anisotropic arrow will be plotted
phi = ckb_model.interp_dep(depth, field='phi', samp_interval=samp_interval) # phi_inv[i,:] are (lon, lat, phi)
epsilon = ckb_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval) # epsilon_inv[i,:] are (lon, lat, epsilon)
ani_lon = phi[:,0].reshape(-1,1)
ani_lat = phi[:,1].reshape(-1,1)
ani_phi = phi[:,2].reshape(-1,1)
length = ((epsilon[:,2] - ani_per_1) / (ani_per_2 - ani_per_1) * scale + basic).reshape(-1,1)
ani_arrow = np.hstack([ani_lon, ani_lat, ani_phi, length, np.ones((ani_lon.size,1))*width]) # lon, lat, color, angle[-90,90], length, width
# remove arrows with small amplitude of anisotropy
idx = np.where(epsilon[:,2] > ani_thd)[0] # indices of arrows with large enough amplitude of anisotropy
ani_arrow = ani_arrow[idx,:] # remove arrows with small amplitude of anisotropy
# plot anisotropic arrows
fig.plot(ani_arrow, style='j', fill='yellow1', pen='0.5p,black') # plot fast velocity direction
fig.text(text="%d km"%(depth), x = 0.2 , y = 0.1, font = "14p,Helvetica-Bold,black", fill = "white")
# plot vertical profile
fig.plot(x=[0.9, 0.9], y=[0, 1], pen="2p,black,-") # vertical line
fig.shift_origin(xshift=0, yshift=-6)
# colorbar
fig.shift_origin(xshift=0, yshift= 4.5)
fig.colorbar(frame = ["a10","y+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.shift_origin(xshift=0, yshift= 1.5)
# ------------ plot horivertical profile of velocity ------------
fig.shift_origin(xshift=11, yshift= 0)
region = [0, 40, 0, 1] # region of interest
fig.basemap(region=region, frame=["xa20+lDepth (km)","ya1+lLatitude","nSwE"], projection="X3c/5c") # base map
start = [0.9,0]; end = [0.9,1]; gap = 1
prof_init = init_model.interp_sec(start, end, field='vel', val = gap) # prof_init[i,:] are (lon, lat, dis, dep, vel)
prof_ckb = ckb_model.interp_sec(start, end, field='vel', val = gap) # prof_ckb[i,:] are (lon, lat, dis, dep, vel)
lat = prof_init[:,1] # lat
dep = prof_init[:,3] # depth
vel = (prof_ckb[:,4] - prof_init[:,4])/prof_init[:,4] * 100 # velocity perturbation related to initial model
grid = pygmt.surface(x=dep, y=lat, z=vel, spacing="1/0.01",region=region)
fig.grdimage(grid = grid) # plot figure
fig.savefig("figs/flexible_checkerboard_velocity.png") # save figure
fig.show()

View File

@@ -0,0 +1,50 @@
version: 3
#################################################
# computational domian #
#################################################
domain:
min_max_dep: [-10, 50] # depth in km
min_max_lat: [0, 1] # latitude in degree
min_max_lon: [0, 2] # longitude in degree
n_rtp: [61, 51, 101] # number of nodes in depth,latitude,longitude direction
#################################################
# traveltime data file path #
#################################################
source:
src_rec_file: 1_src_rec_files/src_rec_config.dat # source receiver file path
swap_src_rec: true # swap source and receiver
#################################################
# initial model file path #
#################################################
model:
init_model_path: 2_models/model_ckb_N61_51_101.h5 # path to initial model file
#################################################
# parallel computation settings #
#################################################
parallel: # parameters for parallel computation
n_sims: 8 # number of simultanoues runs (parallel the sources)
ndiv_rtp: [1, 1, 1] # number of subdivision on each direction (parallel the computional domain)
############################################
# output file setting #
############################################
output_setting:
output_dir: OUTPUT_FILES/OUTPUT_FILES_signal # path to output director (default is ./OUTPUT_FILES/)
output_final_model: true # output merged final model (final_model.h5) or not.
output_in_process: false # output model at each inv iteration or not.
output_in_process_data: false # output src_rec_file at each inv iteration or not.
output_file_format: 0
#################################################
# inversion or forward modeling #
#################################################
# run mode
# 0 for forward simulation only,
# 1 for inversion
# 2 for earthquake relocation
# 3 for inversion + earthquake relocation
run_mode: 0

View File

@@ -0,0 +1,13 @@
#!/bin/bash
# run the script to generate HDF5 model files for TomoATT. Four models will be generated for TomoATT
# 1. constant velocity model
# 2. linear velocity model
# 3. regular checkerboard model based on the linear velocity model
# 4. flexible checkerboard model based on the linear velocity model
python 1_generate_models.py
# run the script to plot the generated models (optional)
python 2_plot_models.py

View File

@@ -0,0 +1,173 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# (Option 1) plot the final model after inversion
# Need to set "output_final_model" as "True" in the input_params.yaml file
# ---------------- read model files ----------------
# file names
init_model_file = 'input_files/model_init_N61_61_61.h5' # initial model file
inv_model_file = 'OUTPUT_FILES/final_model.h5' # final model file
par_file = 'input_files/input_params.yaml' # parameter file
# read initial and final model file
model = ATTModel.read(init_model_file, par_file)
init_model = model.to_xarray()
model = ATTModel.read(inv_model_file, par_file)
inv_model = model.to_xarray()
# %%
# # (Option 2) plot the model at the XX iteration
# # Need to set "output_middle_model" as "True" in the input_params.yaml file
# # ---------------- read model files ----------------
# # file names
# init_model_file = 'input_files/model_init_N61_61_61.h5' # initial model file
# inv_model_file = 'OUTPUT_FILES/middle_model_step_0007.h5' # final model file
# par_file = 'input_files/input_params.yaml' # parameter file
# # read initial and final model file
# model = ATTModel.read(init_model_file, par_file)
# init_model = model.to_xarray()
# model = ATTModel.read(inv_model_file, par_file)
# inv_model = model.to_xarray()
# %%
import os
try:
os.mkdir('img')
except:
pass
# %%
# ---------------- access 3D model parameters ----------------
# we can access 3D dataset with keys:
# 1. "vel" for velocity
# 2. "phi" fast velocity direction, anti-clock angle w.r.t the east direction. (only available for anisotropic model)
# 3. "epsilon" for anisotropic magnitude (only available for anisotropic model)
# 4. "xi" and "eta" for anisotropic parameters: xi = epsilon * cos(phi), eta = epsilon * sin(phi)
vel_3d_array = inv_model["vel"]
phi_3d_array = inv_model["phi"]
epsilon_3d_array = inv_model["epsilon"]
xi_3d_array = inv_model["xi"]
eta_3d_array = inv_model["eta"]
print("3D array of model parameters. \n vel: ", vel_3d_array.shape, " \n phi: ", phi_3d_array.shape,
" \n epsilon: ", epsilon_3d_array.shape, " \n xi: ", xi_3d_array.shape, " \n eta: ", eta_3d_array.shape)
# %%
# ---------------- 2D depth profile of velocity perturbation ----------------
# interp vel at depth = 20 km
depth = 20.0
vel_init = init_model.interp_dep(depth, field='vel') # vel_init[i,:] are (lon, lat, vel)
vel_inv = inv_model.interp_dep(depth, field='vel')
print("vel_depth at depth = ", depth, " km. vel_depth:", vel_init.shape, ", (lon, lat, vel)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","+tVelocity perturbation"], projection="M10c") # base map
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-20, 20], background=True, reverse=False) # colorbar
x = vel_init[:,0]; # longitude
y = vel_init[:,1]; # latitude
value = (vel_inv[:,2] - vel_init[:,2])/vel_init[:,2] * 100 # velocity perturbation relative to the initial model
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 = ["a20","y+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.savefig("img/1_dep_vel.png")
# %%
# ---------------- 2D depth profile of azimuthal anisotropy ----------------
# interp magnitude of anisotropy at depth = 20 km
depth = 20.0
epsilon_inv = inv_model.interp_dep(depth, field='epsilon') # epsilon_inv[i,:] are (lon, lat, epsilon)
print("epsilon_inv at depth = ", depth, " km. epsilon_inv:", epsilon_inv.shape, ", (lon, lat, epsilon)")
# generate fast velocity direction (anisotropic arrow)
samp_interval = 3
length = 10
width = 0.1
ani_thd = 0.02
ani_phi = inv_model.interp_dep(depth, field='phi', samp_interval=samp_interval)
ani_epsilon = inv_model.interp_dep(depth, field='epsilon', samp_interval=samp_interval)
ani_arrow = np.hstack([ani_phi, ani_epsilon[:,2].reshape(-1, 1)*length, np.ones((ani_epsilon.shape[0],1))*width]) # lon, lat, angle, length, width
idx = np.where(ani_epsilon[:,2] > ani_thd)
ani_arrow = ani_arrow[idx[0],:]
print("ani_arrow at depth = ", depth, " km. ani_arrow:", ani_arrow.shape, ", (lon, lat, angle, length, width)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","+tAzimuthal Anisotropy"], projection="M10c") # base map
pygmt.makecpt(cmap="cool", series=[0, 0.1], background=True, reverse=False) # colorbar
x = epsilon_inv[:,0]; # longitude
y = epsilon_inv[:,1]; # latitude
value = epsilon_inv[:,2] # magnitude of anisotropy
grid = pygmt.surface(x=x, y=y, z=value, spacing=0.04,region=[0,2,0,2])
fig.grdimage(grid = grid) # plot magnitude of anisotropy
fig.plot(ani_arrow, style='j', fill='yellow1', pen='0.5p,black') # plot fast velocity direction
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.1","y+lAnisotropy"], position="+e+w4c/0.3c+h")
fig.savefig("img/1_dep_ani.png")
# %%
# ---------------- 2D vertical profile of velocity perturbation ----------------
# interp vel from [0,0.75] in lon-lat to [2,0.75] in lon-lat, gap = 1 km
start = [0,0.75]; end = [2,0.75]; gap = 1
vel_init_sec = init_model.interp_sec(start, end, field='vel', val = gap) # vel_init_sec[i,:] are (lon, lat, dis, dep, vel)
vel_inv_sec = inv_model.interp_sec(start, end, field='vel', val = gap)
print("vel_init_sec:", vel_init_sec.shape, ", (lon, lat, distance, depth, vel)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,40], frame=["xa1+lLongitude","ya20+lDepth (km)","+tVelocity perturbation"], projection="X10c/-4c") # base map
pygmt.makecpt(cmap="../utils/svel13_chen.cpt", series=[-20, 20], background=True, reverse=False) # colorbar
x = vel_init_sec[:,0]; # longitude
y = vel_init_sec[:,3]; # depth
value = (vel_inv_sec[:,4] - vel_init_sec[:,4])/vel_init_sec[:,4] * 100 # velocity perturbation relative to the initial model
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 = ["a20","y+ldlnVp (%)"], position="+e+w4c/0.3c+h")
fig.savefig("img/1_sec_vel.png")

View File

@@ -0,0 +1,187 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# plot the traveltime field and adjoint field of the source at the XX iteration
# 1. set "output_source_field" to be "True" in the input_params.yaml file
# Because source parallelizaion is used, the source field is only stored in one out_data_sim_group_XX.h5 file.
# For example, if we use 8 processors for source parallelization, we have
# src_JC00 is stored in out_data_sim_group_0.h5 file.
# src_JC05 is stored in out_data_sim_group_5.h5 file.
# src_JC07 is stored in out_data_sim_group_7.h5 file.
# src_JC08 is stored in out_data_sim_group_0.h5 file.
# src_JC09 is stored in out_data_sim_group_1.h5 file.
# src_JC10 is stored in out_data_sim_group_2.h5 file.
# ...
# src_JC24 is stored in out_data_sim_group_0.h5 file.
# ---------------- read files ----------------
src_name = 'JC05'
Nstep = "0007"
# file names
data_file = 'OUTPUT_FILES/out_data_sim_group_5.h5' # data file
par_file = 'input_files/input_params.yaml' # parameter file
grid_file = 'OUTPUT_FILES/out_data_grid.h5' # grid file
group = 'src_%s'%(src_name) # src_${src_name}
# read traveltime field
dataset_time = 'time_field_inv_%s'%(Nstep) # time_field_inv_${Nstep}
data = ATTData.read(data_file, par_file, grid_file, group, dataset_time)
time_field = data.to_xarray()
# read adjoint field
dataset_adjoint = 'adjoint_field_inv_%s'%(Nstep) # adjoint_field_inv_${Nstep}
data = ATTData.read(data_file, par_file, grid_file, group, dataset_adjoint)
adjoint_field = data.to_xarray()
# %%
import os
try:
os.mkdir('img')
except:
pass
# %%
# ---------------- access 3D time field and adjoint field ----------------
# we can access 3D dataset:
dep_1d_array = time_field["dep"]
lat_1d_array = time_field["lat"]
lon_1d_array = time_field["lon"]
print("3D array of coordinates. \n dep: ", dep_1d_array.shape, " \n lat: ", lat_1d_array.shape, " \n lon: ", lon_1d_array.shape)
time_3d_array = time_field[dataset_time]
adjoint_3d_array = adjoint_field[dataset_adjoint]
print("3D array of fields. \n time: ", time_3d_array.shape, " \n adjoint: ", adjoint_3d_array.shape)
# %%
# ---------------- 2D depth profile of time field ----------------
# interp vel at depth = 20 km
depth = 20.0
time = time_field.interp_dep(depth, field=dataset_time) # time[i,:] are (lon, lat, vel)
print("time at depth = ", depth, " km. time:", time.shape, ", (lon, lat, time)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","+tTraveltime"], projection="M10c") # base map
pygmt.makecpt(cmap="jet", series=[0, 30], background=True, reverse=True) # colorbar
x = time[:,0]; # longitude
y = time[:,1]; # latitude
value = time[:,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.contour(x=x, y=y, z=value, levels=5, pen="1.5p,white") # contour
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 = ["a20","y+lTraveltime (s)"], position="+e+w4c/0.3c+h")
fig.savefig("img/2_dep_time.png")
# %%
# ---------------- 2D depth profile of adjoint field ----------------
# interp vel at depth = 20 km
depth = 20.0
adjoint = adjoint_field.interp_dep(depth, field=dataset_adjoint)
print("time at depth = ", depth, " km. time:", time.shape, ", (lon, lat, time)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","+tAdjoint field"], projection="M10c") # base map
pygmt.makecpt(cmap="jet", series=[-0.5, 0.5], background=True, reverse=False) # colorbar
x = time[:,0]; # longitude
y = time[:,1]; # latitude
value = adjoint[:,2] # traveltime
value = value/np.nanmax(np.abs(value))
grid = pygmt.surface(x=x, y=y, z=value, spacing=0.04,region=[0,2,0,2])
fig.grdimage(grid = grid) # plot figure
fig.contour(x=x, y=y, z=time[:,2], levels=5, pen="1.5p,white") # contour
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+lAdjoint field"], position="+e+w4c/0.3c+h")
fig.savefig("img/2_dep_adjoint.png")
# %%
# ---------------- 2D vertical profile of traveltime field ----------------
# 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
time_sec = time_field.interp_sec(start, end, field=dataset_time, val = gap) # time_sec[i,:] are (lon, lat, dis, dep, time)
print("time_sec:", time_sec.shape, ", (lon, lat, distance, depth, time)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,40], frame=["xa1+lLongitude","ya20+lDepth (km)","+tTraveltime"], projection="X10c/-2c") # base map
pygmt.makecpt(cmap="jet", series=[0, 30], background=True, reverse=True) # colorbar
x = time_sec[:,0]; # longitude
y = time_sec[:,3]; # depth
value = time_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.contour(x=x, y=y, z=value, levels=5, pen="1.5p,white") # contour
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 = ["a20","y+lTraveltime (s)"], position="+e+w4c/0.3c+h")
fig.savefig("img/2_sec_time.png")
# %%
# ---------------- 2D vertical profile of adjoint field ----------------
# 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
adjoint_sec = adjoint_field.interp_sec(start, end, field=dataset_adjoint, val = gap)
print("adjoint_sec:", time_sec.shape, ", (lon, lat, distance, depth, adjoint)")
# plot
fig = pygmt.Figure()
fig.basemap(region=[0,2,0,40], frame=["xa1+lLongitude","ya20+lDepth (km)","+tAdjoint field"], projection="X10c/-2c") # base map
pygmt.makecpt(cmap="jet", series=[-0.5, 0.5], background=True, reverse=False) # colorbar
x = adjoint_sec[:,0]; # longitude
y = adjoint_sec[:,3]; # depth
value = adjoint_sec[:,4] # traveltime
value = value/np.nanmax(np.abs(value))
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.contour(x=x, y=y, z=time_sec[:,4], levels=5, pen="1.5p,white") # contour
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+lAdjoint"], position="+e+w4c/0.3c+h")
fig.savefig("img/2_sec_adjoint.png")

View File

@@ -0,0 +1,189 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
from pytomoatt.model import ATTModel
from pytomoatt.data import ATTData
import numpy as np
# %%
# plot sensitivity kernel at the XX iteration
# 1. set "output_kernel" to be "True" in the input_params.yaml file
# ---------------- 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'
# (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()
# %%
# (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()
# %%
# kernel density normalization is performed after smoothing. So tag 'Ks_over_Kden_inv_%s'%(Nstep) is not available for version > 1.0.3
# # (Option 3) read normalized kernel, K/(k_den)^\zeta
# dataset = 'Ks_over_Kden_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# # Kxi_norm: normalized kernel w.r.t. xi (anisotropic parameter) at the 7-th iteration
# dataset = 'Kxi_over_Kden_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# # Keta_norm: normalized kernel w.r.t. eta (anisotropic parameter) at the 7-th iteration
# dataset = 'Keta_over_Kden_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# %%
# this part works for version > 1.0.3
# # (Option 3) read kernel density smoothed by multigrid parameterization,
# dataset = 'Ks_density_update_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# # Kxi_norm: normalized kernel w.r.t. xi (anisotropic parameter) at the 7-th iteration
# dataset = 'Kxi_density_update_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# # Keta_norm: normalized kernel w.r.t. eta (anisotropic parameter) at the 7-th iteration
# dataset = 'Keta_density_update_inv_%s'%(Nstep)
# data = ATTData.read(data_file, par_file, grid_file, group, dataset)
# kernel_list[dataset] = data.to_xarray()
# %%
# (Option 4) 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()
# %%
import os
try:
os.mkdir('img')
except:
pass
# %%
# ---------------- 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)
# %%
# ---------------- 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))
# %%
# ---------------- 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))

View File

@@ -0,0 +1,54 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
# %%
from pytomoatt.src_rec import SrcRec
# read src_rec_file
sr = SrcRec.read("input_files/src_rec_file.dat")
# get the coordinates of the stations and earthquakes
stations = sr.receivers[['stlo','stla','stel']].values.T
earthquakes = sr.sources[['evlo','evla','evdp']].values.T
print(stations.shape)
print(earthquakes.shape)
# %%
# plot earthquakes and locations
fig = pygmt.Figure()
pygmt.makecpt(cmap="jet", series=[0, 40], background=True, reverse=True) # colorbar
# -------- horizontal view (x-y) --------
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","NsWe"], projection="M10c") # base map
# earthquakes
fig.plot(x = earthquakes[0,:], y = earthquakes[1,:], cmap = True, style = "c0.1c", fill = earthquakes[2,:])
# stations
fig.plot(x = stations[0,:], y = stations[1,:], style = "t0.4c", fill = "blue", pen = "black", label = "Station")
# -------- vertical view (x-z) --------
fig.shift_origin(xshift=0, yshift=-3)
fig.basemap(region=[0,2,0,40], frame=["xa1","ya20+lDepth (km)","NsWe"], projection="X10c/-2c") # base map
# earthquakes
fig.plot(x = earthquakes[0,:], y = earthquakes[2,:], cmap = True, style = "c0.1c", fill = earthquakes[2,:])
# -------- vertical view (z-y) --------
fig.shift_origin(xshift=11, yshift=3)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","NsWe"], projection="X2c/10c") # base map
# earthquakes
fig.plot(x = earthquakes[2,:], y = earthquakes[1,:], cmap = True, style = "c0.1c", fill = earthquakes[2,:])
# colorbar
fig.shift_origin(xshift=0, yshift=-1.5)
fig.colorbar(frame = ["a20","x+lDepth (km)"], position="+e+w2c/0.3c+h")
fig.savefig("img/4_earthquakes_and_stations.png")

View File

@@ -0,0 +1,124 @@
# %%
import sys
sys.path.append('../utils')
import functions_for_data as ffd
# %%
# read objective function
path = "OUTPUT_FILES"
full_curve, location_curve, model_curve = ffd.read_objective_function_file(path)
print("full_curve: ", full_curve.shape, ", the total objective function value during the inversion, including relocation and model update")
print("location_curve: ", location_curve.shape, ", the objective function value during the relocation step")
print("model_curve: ", model_curve.shape, ", the objective function value during the model update step")
print("The first index is iteraion number, the second index is the objective function value vector")
# %%
# (Option 1) objective function value
full_obj = full_curve[:,0]
location_obj = location_curve[:,0]
model_obj = model_curve[:,0]
# (Option 2) objective function value for only traveltime
full_obj_tt = full_curve[:,1]
location_obj_tt = location_curve[:,1]
model_obj_tt = model_curve[:,1]
# (Option 3) objective function value for only common source differential arrival time
full_obj_cs = full_curve[:,2]
location_obj_cs = location_curve[:,2]
model_obj_cs = model_curve[:,2]
# (Option 4) objective function value for only common receiver differential arrival time
full_obj_cr = full_curve[:,3]
location_obj_cr = location_curve[:,3]
model_obj_cr = model_curve[:,3]
# (Option 5) objective function value for teleseismic differential arrival time
full_obj_tele = full_curve[:,4]
location_obj_tele = location_curve[:,4]
model_obj_tele = model_curve[:,4]
# (Option 6) mean value of all data residual
full_mean = full_curve[:,5]
location_mean = location_curve[:,5]
model_mean = model_curve[:,5]
# (Option 7) standard deviation of all data residual
full_std = full_curve[:,6]
location_std = location_curve[:,6]
model_std = model_curve[:,6]
# (Option 8) mean value of residuals of traveltime
full_mean_tt = full_curve[:,7]
location_mean_tt = location_curve[:,7]
model_mean_tt = model_curve[:,7]
# (Option 9) standard deviation of residuals of traveltime
full_std_tt = full_curve[:,8]
location_std_tt = location_curve[:,8]
model_std_tt = model_curve[:,8]
# (Option 10) mean value of residuals of common source differential arrival time
full_mean_cs = full_curve[:,9]
location_mean_cs = location_curve[:,9]
model_mean_cs = model_curve[:,9]
# (Option 11) standard deviation of residuals of common source differential arrival time
full_std_cs = full_curve[:,10]
location_std_cs = location_curve[:,10]
model_std_cs = model_curve[:,10]
# (Option 12) mean value of residuals of common receiver differential arrival time
full_mean_cr = full_curve[:,11]
location_mean_cr = location_curve[:,11]
model_mean_cr = model_curve[:,11]
# (Option 13) standard deviation of residuals of common receiver differential arrival time
full_std_cr = full_curve[:,12]
location_std_cr = location_curve[:,12]
model_std_cr = model_curve[:,12]
# (Option 14) mean value of residuals of teleseismic differential arrival time
full_mean_tele = full_curve[:,13]
location_mean_tele = location_curve[:,13]
model_mean_tele = model_curve[:,13]
# (Option 15) standard deviation of residuals of teleseismic differential arrival time
full_std_tele = full_curve[:,14]
location_std_tele = location_curve[:,14]
model_std_tele = model_curve[:,14]
# %%
import os
try:
os.mkdir("img")
except:
pass
# %%
# plot objective functin reduction
import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(10, 6))
ax = plt.subplot(1, 1, 1)
ax.plot(model_obj/np.max(model_obj), label='objective function', linewidth=2)
ax.set_xlim([-0.2, len(model_obj)-0.8])
ax.set_ylim([0, 1.1])
ax.grid()
ax.set_xlabel('Iteration number',fontsize=14)
ax.set_ylabel('Normalized value',fontsize=14)
ax.tick_params(axis='x', labelsize=14)
ax.tick_params(axis='y', labelsize=14)
ax.legend(fontsize=14)
plt.savefig('img/5_objective_function_reduction.png', dpi=300, bbox_inches='tight', edgecolor='w', facecolor='w')

View File

@@ -0,0 +1,86 @@
# %%
import sys
sys.path.append('../utils')
import functions_for_data as ffd
# %%
# synthetic and observational traveltime files in the initial and final models
file_init_syn = "OUTPUT_FILES/src_rec_file_inv_0000_reloc_0000.dat" # synthetic traveltime in the initial model
file_init_obs = "input_files/src_rec_file.dat" # observational traveltime in the initial model
file_final_syn = "OUTPUT_FILES/src_rec_file_inv_0009_reloc_0009.dat" # synthetic traveltime in the final model
file_final_obs = "OUTPUT_FILES/src_rec_file_inv_0009_reloc_0009_obs.dat" # observational traveltime in the final model
# %%
# from pytomoatt.src_rec import SrcRec
# init_syn = SrcRec.read(file_init_syn)
# init_obs = SrcRec.read(file_init_obs)
# final_syn = SrcRec.read(file_final_syn)
# final_obs = SrcRec.read(file_final_obs)
# %%
ev, st = ffd.read_src_rec_file(file_init_syn)
time_init_syn = ffd.data_dis_time(ev, st)[1] # synthetic traveltime in the initial model
ev, st = ffd.read_src_rec_file(file_init_obs)
time_init_obs = ffd.data_dis_time(ev, st)[1] # observational traveltime in the initial model
ev, st = ffd.read_src_rec_file(file_final_syn)
time_final_syn = ffd.data_dis_time(ev, st)[1] # synthetic traveltime in the final model
ev, st = ffd.read_src_rec_file(file_final_obs)
time_final_obs = ffd.data_dis_time(ev, st)[1] # observational traveltime in the final model
# %%
import os
try:
os.mkdir("img")
except:
pass
# %%
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(111)
range_l = -1.5
range_r = 1.5
Nbar = 20
bins=np.linspace(range_l,range_r,Nbar)
error_init = time_init_syn - time_init_obs
error_final = time_final_syn - time_final_obs
tag1 = "initial mode"
tag2 = "final mode"
hist_init, _, _ = ax.hist(error_init,bins=bins,histtype='step', edgecolor = "red", linewidth = 2,
label = "%s: std = %5.3f s, mean = %5.3f s"%(tag1,np.std(error_init),np.mean(error_init)))
hist_final, _, _ = ax.hist(error_final,bins=bins,alpha = 0.5, color = "blue",
label = "%s: std = %5.3f s, mean = %5.3f s"%(tag2,np.std(error_final),np.mean(error_final)))
print("residual for ",tag1," model is: ","mean: ",np.mean(error_init),"sd: ",np.std(error_init))
print("residual for ",tag2," model is: ","mean: ",np.mean(error_final),"sd: ",np.std(error_final))
ax.legend(fontsize=14)
ax.set_xlim(range_l - abs(range_l)*0.1,range_r + abs(range_r)*0.1)
ax.set_ylim(0,1.3*max(max(hist_init),max(hist_final)))
ax.tick_params(axis='x',labelsize=18)
ax.tick_params(axis='y',labelsize=18)
ax.set_ylabel('Count of data',fontsize=18)
ax.set_xlabel('Traveltime residuals (s)',fontsize=18)
ax.set_title("$t_{syn} - t_{obs}$",fontsize=18)
ax.grid()
plt.savefig("img/6_data_residual.png",dpi=300, bbox_inches='tight', edgecolor='w', facecolor='w' )
plt.show()

View File

@@ -0,0 +1,61 @@
# %%
import pygmt
pygmt.config(FONT="16p", IO_SEGMENT_MARKER="<<<")
# %%
import sys
sys.path.append('../utils')
import functions_for_data as ffd
# %%
# read inversion grid file
inv_grid_vel, inv_grid_ani = ffd.read_inversion_grid_file("OUTPUT_FILES")
print("inversion grid for velocity: ", inv_grid_vel.shape)
print("inversion grid for anisotropy: ", inv_grid_vel.shape)
Nset = inv_grid_vel.shape[0]
Ngrid = inv_grid_vel.shape[1]
colorlist = ["green","blue","red","purple","orange","yellow","black","gray","pink","cyan"]
# %%
# plot earthquakes and locations
fig = pygmt.Figure()
pygmt.makecpt(cmap="jet", series=[0, 40], background=True, reverse=True) # colorbar
# -------- horizontal view (x-y) --------
fig.basemap(region=[0,2,0,2], frame=["xa1","ya1","NsWe"], projection="M10c") # base map
# plot inversion grid
for igrid in range(Nset):
x = inv_grid_vel[igrid,:,0]
y = inv_grid_vel[igrid,:,1]
fig.plot(x=x, y=y, style="c0.1c", fill=colorlist[igrid])
# -------- vertical view (x-z) --------
fig.shift_origin(xshift=0, yshift=-3)
fig.basemap(region=[0,2,0,40], frame=["xa1","ya20+lDepth (km)","NsWe"], projection="X10c/-2c") # base map
# plot inversion grid
for igrid in range(Nset):
x = inv_grid_vel[igrid,:,0]
y = inv_grid_vel[igrid,:,2]
fig.plot(x=x, y=y, style="c0.1c", fill=colorlist[igrid])
# -------- vertical view (z-y) --------
fig.shift_origin(xshift=11, yshift=3)
fig.basemap(region=[0,40,0,2], frame=["xa20+lDepth (km)","ya1","NsWe"], projection="X2c/10c") # base map
# plot inversion grid
for igrid in range(Nset):
x = inv_grid_vel[igrid,:,2]
y = inv_grid_vel[igrid,:,1]
fig.plot(x=x, y=y, style="c0.1c", fill=colorlist[igrid])
fig.savefig("img/7_inversion_grid.png")

View File

@@ -0,0 +1,16 @@
# Scripts of plotting
It includes examples to illustrate the output file of TomoATT
Python modules are required to initiate the inversion and to plot final results:
- h5py
- PyTomoAT
- Pygmt
- gmt
Run this example:
1. Run bash script `bash run_this_example.sh` to execute the test.

View File

@@ -0,0 +1,21 @@
# %%
# download model file from Zenodo
import os
import requests
url = 'https://zenodo.org/records/14160818/files/files_for_plotting.tar.gz?download=1'
path = "files_for_plotting.tar.gz"
# check file existence
if not os.path.exists(path):
print("Downloading src_rec_file.dat from Zenodo...")
print("The file is about 400 MB, so it may take a while.")
response = requests.get(url, stream=True)
with open(path, 'wb') as out_file:
out_file.write(response.content)
print("Download complete.")
else:
print("files_for_plotting.tar.gz already exists.")

View File

@@ -0,0 +1,50 @@
#!/bin/bash
# Some script to plot figures for the output file of TomoATT
python prepare_files.py # download the files for plotting
tar -xf files_for_plotting.tar.gz # extract the files
# Test 1: plot velocity perturbation and azimuthal anisotropy fields to generate
# img/1_dep_vel.png 2D velocity perturbation at 20 km depth
# img/1_dep_ani.png 2D azimuthal anisotropy at 20 km depth
# img/1_sec_vel.png 2D velocity perturbation along vertical section
python 1_plot_model.py
# Test 2: plot traveltime and adjoint fields to generate
# img/2_dep_time.png 2D traveltime field at 20 km depth
# img/2_sec_time.png 2D traveltime field along vertical section
# img/2_dep_adjoint.png 2D adjoint field at XX depth
# img/2_sec_adjoint.png 2D adjoint field along vertical section
python 2_plot_time_field.py
# Test 3: plot kernels to generate
# img/3_dep_Ks_inv_0007.png Ks: original kernel w.r.t slowness at 20 km depth
# img/3_dep_Ks_density_inv_0007.png Kden: kernel density w.r.t slowness at 20 km depth
# img/3_dep_Ks_over_Kden_inv_0007.png Ks/Kden^{\zeta}: normalized kernel w.r.t slowness at 20 km depth
# img/3_dep_Ks_update_inv_0007.png smoothed normalized kernel w.r.t slowness at 20 km depth
# img/3_sec_Ks_inv_0007.png Ks: original kernel w.r.t slowness along vertical section
# img/3_sec_Ks_density_inv_0007.png Kden: kernel density w.r.t slowness along vertical section
# img/3_sec_Ks_over_Kden_inv_0007.png Ks/Kden^{\zeta}: normalized kernel w.r.t slowness along vertical section
# img/3_sec_Ks_update_inv_0007.png smoothed normalized kernel w.r.t slowness along vertical section
# and the same for kernels w.r.t xi and eta (azimuthal anisotropy)
python 3_plot_kernel.py
# Test 4: plot earthquakes and stations to generate
# img/4_earthquakes_and_stations.png the location of earthquakes and stations
python 4_plot_earthquake_station.py
# Test 5: plot objective function reduction to generate
# img/5_objective_function_reduction.png the reduction of objective function value
python 5_plot_objective_function.py
# Test 6: plot traveltime residuals to generate
# img/6_data_residual.png the traveltime residuals
python 6_plot_data_residual.py
# Test 7: plot inversion grid to generate
# img/7_inversion_grid.png the inversion grid
python 7_plot_inversion_grid.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
-0.7000E+01 166 0 0 -0.6000E+01 225 0 0
-0.6000E+01 225 0 0 -0.5000E+01 255 75 0
-0.5000E+01 255 75 0 -0.4000E+01 255 132 0
-0.4000E+01 255 132 0 -0.3000E+01 255 198 0
-0.3000E+01 255 198 0 -0.2000E+01 255 255 0
-0.2000E+01 255 255 0 -0.1000E+00 255 255 255
-0.1000E+00 255 255 255 0.1000E+00 255 255 255
0.1000E+00 255 255 255 0.2000E+01 0 255 255
0.2000E+01 0 255 255 0.3000E+01 90 205 255
0.3000E+01 90 205 255 0.4000E+01 26 160 255
0.4000E+01 26 160 255 0.5000E+01 0 100 255
0.5000E+01 0 100 255 0.6000E+01 0 50 200
0.6000E+01 0 50 200 0.7000E+01 0 10 160
B 166 0 0
F 0 10 160