Note
Go to the end to download the full example code
1D Rayleigh wave phase velocity inversion#
If you are running this notebook locally, make sure you’ve followed steps here to set up the environment. (This environment.yml file specifies a list of packages required to run the notebooks)
What we do in this notebook#
Here we look at applying CoFI to the inversion of Rayleigh wave phase velocities for a 1D layered earth.
Learning outcomes
A demonstration of CoFI’s ability to switch between parameter estimation and ensemble methods.
A comparison between different McMC samplers that is fixed-d and trans-d samplers
An application of CoFI to field data
# -------------------------------------------------------- #
# #
# Uncomment below to set up environment on "colab" #
# #
# -------------------------------------------------------- #
# !pip install -U cofi git+https://github.com/inlab-geo/pysurf96.git
# !git clone https://github.com/inlab-geo/cofi-examples.git
# %cd cofi-examples/examples/sw_rf_joint
import numpy as np
import scipy
import matplotlib.pyplot as plt
from pysurf96 import surf96
import bayesbay
import cofi
Problem description#
Here we illustrate the range of inversion methods made avaialbe by CoFI. That is we first define a base problem and then explore the use of an iterative non linear apporach to find the MAP solution and then employ a range of Markov Chain Monte Carlo strategies to recover the posterior distribution. The forward problem is solved using pysurf 96 (miili/pysurf96) and the field data example is taken from (https://www.eas.slu.edu/eqc/eqc_cps/TUTORIAL/STRUCT/index.html) and we will be inverting observed rayleigh wave phase velocities
Inference problem
# display theory on the inference problem
from IPython.display import display, Markdown
with open("../../theory/geo_surface_wave_dispersion.md", "r") as f:
content = f.read()
display(Markdown(content))
<IPython.core.display.Markdown object>
Solving methods
# display theory on the optimisation approach
with open("../../theory/inv_optimisation.md", "r") as f:
content = f.read()
display(Markdown(content))
<IPython.core.display.Markdown object>
# display theory on the optimisation approach
with open("../../theory/inv_mcmc.md", "r") as f:
content = f.read()
display(Markdown(content))
<IPython.core.display.Markdown object>
Further reading
Utilities#
1D model paramterisation#
# display theory on the 1D model parameterisation
with open("../../theory/misc_1d_model_parameterisation.md", "r") as f:
content = f.read()
display(Markdown(content))
<IPython.core.display.Markdown object>
def voronoi_to_layercake(voronoi_vector: np.ndarray) -> np.ndarray:
n_layers = len(voronoi_vector) // 2
velocities = voronoi_vector[:n_layers]
voronoi_sites = voronoi_vector[n_layers:]
depths = (voronoi_sites[:-1] + voronoi_sites[1:]) / 2
thicknesses = depths - np.insert(depths[:-1], 0, 0)
layercake_vector = np.zeros((2*n_layers-1,))
layercake_vector[::2] = velocities
layercake_vector[1::2] = thicknesses
return layercake_vector
def layercake_to_voronoi(layercake_vector: np.ndarray, first_voronoi_site: float = 0.0) -> np.ndarray:
n_layers = len(layercake_vector) // 2 + 1
thicknesses = layercake_vector[1::2]
velocities = layercake_vector[::2]
depths = np.cumsum(thicknesses)
voronoi_sites = np.zeros((n_layers,))
for i in range(1,len(voronoi_sites)):
voronoi_sites[i] = 2 * depths[i-1] - voronoi_sites[i-1]
voronoi_vector = np.hstack((velocities, voronoi_sites))
return voronoi_vector
Forward solver#
# display theory on the using the forward solver
with open("../../theory/geo_surface_wave_dispersion2.md", "r") as f:
content = f.read()
display(Markdown(content))
<IPython.core.display.Markdown object>
# Constants
VP_VS = 1.77
RHO_VP_K = 0.32
RHO_VP_B = 0.77
# forward through pysurf96
def forward_sw(model, periods):
thicknesses, vs = split_layercake_model(model)
thicknesses = np.append(thicknesses, 10)
vp = vs * VP_VS
rho = RHO_VP_K * vp + RHO_VP_B
return surf96(
thicknesses,
vp,
vs,
rho,
periods,
wave="rayleigh",
mode=1,
velocity="phase",
flat_earth=False,
)
# numerical jacobian
def jacobian_sw(model, periods, fwd=forward_sw, relative_step=0.01):
jacobian = np.zeros((len(periods), len(model)))
original_dpred = fwd(model, periods)
for i in range(len(model)):
perturbed_model = model.copy()
step = relative_step * model[i]
perturbed_model[i] += step
perturbed_dpred = fwd(perturbed_model, periods)
derivative = (perturbed_dpred - original_dpred) / abs(step)
jacobian[:, i] = derivative
return jacobian
Visualisation#
For conveninece we also implement two functions to plot the data here the Rayleigh wave phase velocity and a model given in the layer based parametrisation.
def plot_model(model, ax=None, title="model", **kwargs):
# process data
thicknesses = np.append(model[1::2], max(model[1::2]))
velocities = model[::2]
y = np.insert(np.cumsum(thicknesses), 0, 0)
x = np.insert(velocities, 0, velocities[0])
# plot depth profile
if ax is None:
_, ax = plt.subplots()
plotting_style = {
"linewidth": kwargs.pop("linewidth", kwargs.pop("lw", 0.5)),
"alpha": 0.2,
"color": kwargs.pop("color", kwargs.pop("c", "blue")),
}
plotting_style.update(kwargs)
ax.step(x, y, where="post", **plotting_style)
if ax.get_ylim()[0] < ax.get_ylim()[1]:
ax.invert_yaxis()
ax.set_xlabel("Vs (km/s)")
ax.set_ylabel("Depth (km)")
ax.set_title(title)
return ax
def plot_data(rayleigh_phase_velocities, periods, ax=None, scatter=False,
title="data", **kwargs):
if ax is None:
_, ax = plt.subplots()
plotting_style = {
"linewidth": kwargs.pop("linewidth", kwargs.pop("lw", 1)),
"alpha": 1,
"color": kwargs.pop("color", kwargs.pop("c", "blue")),
}
plotting_style.update(**kwargs)
if scatter:
ax.scatter(periods, rayleigh_phase_velocities, **plotting_style)
else:
ax.plot(periods, rayleigh_phase_velocities, **plotting_style)
ax.set_xlabel("Periods (s)")
ax.set_ylabel("Rayleigh phase velocities (km/s)")
ax.set_title(title)
return ax
def plot_model_and_data(model, label_model, color_model,
forward_func, periods, label_d_pred, color_d_pred,
axes=None, light_thin=False):
if axes is None:
_, axes = plt.subplots(1, 2, figsize=(10, 4), gridspec_kw={"width_ratios": [1, 2.5]})
ax1, ax2 = axes
if light_thin:
plot_model(model, ax=ax1, color=color_model, alpha=0.2, lw=0.5, label=label_model)
plot_data(forward_func(model, periods), periods, ax=ax2, color=color_d_pred, alpha=0.2, lw=0.5, label=label_d_pred)
else:
plot_model(model, ax=ax1, color=color_model, alpha=1, lw=1, label=label_model)
plot_data(forward_func(model, periods), periods, ax=ax2, color=color_d_pred, label=label_d_pred)
ax1.legend()
ax2.legend()
return ax1, ax2
Synthetic example#
Prior to inverting any field data it is good practice to test an inversion method using sythetic exmaples where we know the true model. It is also recommended to prior to this idnepently test any forward solver that is being used and verify the Jacobian, as problems related to the forward sovler are diffiuclt to identify and diagnose once they are integrated in an inversion methodology.
Generate synthetic data#
synth_d_periods = np.geomspace(3, 80, 20)
true_thicknesses = np.array([10, 10, 15, 20, 20, 20, 20, 20])
true_vs = np.array([3.38, 3.44, 3.66, 4.25, 4.35, 4.32, 4.315, 4.38, 4.5])
true_model = form_layercake_model(true_thicknesses, true_vs)
noise_level = 0.02
d_true = forward_sw(true_model, synth_d_periods)
d_obs = d_true + np.random.normal(0, 0.01, len(d_true))
# plot true model and d_pred from true model
_, ax2 = plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="true data (noiseless)", color_d_pred="orange")
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=ax2, scatter=True, color="red", s=20, label="observed data (noisy)")
ax2.legend();
<matplotlib.legend.Legend object at 0x7fd0a7ff0410>
Optimisation#
Prepare ``BaseProblem`` for optimisation
n_dims = 17
init_thicknesses = np.ones((n_dims//2,)) * 15
init_vs = np.ones((n_dims//2+1,)) * 4.0
init_model = form_layercake_model(init_thicknesses, init_vs)
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="purple",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="data predictions from starting model", color_d_pred="purple")
# plot the model and d_pred for true model
plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="true data (noiseless)", color_d_pred="orange", axes=axes)
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=axes[1], scatter=True, color="red", s=20, label="d_obs")
axes[1].legend();
<matplotlib.legend.Legend object at 0x7fd24e265950>
my_reg = cofi.utils.QuadraticReg(
weighting_matrix="damping",
model_shape=(n_dims,),
reference_model=init_model
)
def my_objective(model, fwd, periods, d_obs, lamda=1.0):
d_pred = fwd(model, periods)
data_misfit = np.sum((d_obs - d_pred) ** 2)
reg = my_reg(model)
return data_misfit + lamda * reg
def my_objective_gradient(model, fwd, periods, d_obs, lamda=1.0):
d_pred = fwd(model, periods)
jac = jacobian_sw(model, periods, fwd)
data_misfit_grad = -2 * jac.T @ (d_obs - d_pred)
reg_grad = my_reg.gradient(model)
return data_misfit_grad + lamda * reg_grad
def my_objective_hessian(model, fwd, periods, d_obs, lamda=1.0):
jac = jacobian_sw(model, periods, fwd)
data_misfit_hess = 2 * jac.T @ jac
reg_hess = my_reg.hessian(model)
return data_misfit_hess + lamda * reg_hess
Optimisation with no damping#
lamda = 0
kwargs = {
"fwd": forward_sw,
"periods": synth_d_periods,
"d_obs": d_obs,
"lamda": lamda
}
sw_problem_no_reg = cofi.BaseProblem()
sw_problem_no_reg.set_objective(my_objective, kwargs=kwargs)
sw_problem_no_reg.set_gradient(my_objective_gradient, kwargs=kwargs)
sw_problem_no_reg.set_hessian(my_objective_hessian, kwargs=kwargs)
sw_problem_no_reg.set_initial_model(init_model)
Define ``InversionOptions``
inv_options_optimiser = cofi.InversionOptions()
inv_options_optimiser.set_tool("scipy.optimize.minimize")
inv_options_optimiser.set_params(method="trust-exact")
Define ``Inversion`` and run
inv_optimiser_no_reg = cofi.Inversion(sw_problem_no_reg, inv_options_optimiser)
inv_result_optimiser_no_reg = inv_optimiser_no_reg.run()
Plot results
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from true model", color_d_pred="orange", axes=axes)
# plot the model and d_pred for inverted model
plot_model_and_data(model=inv_result_optimiser_no_reg.model, label_model="inverted model", color_model="purple",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from inverted model", color_d_pred="purple", axes=axes);
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=axes[1], scatter=True, color="red", s=20, label="d_obs")
axes[1].legend();
<matplotlib.legend.Legend object at 0x7fd24e886450>
Optimal damping#
Obviously we get a very skewed 1D model out of an optimisation that solely tries to minimise the data misfit. We would like to add a damping term to our objective function, but we are not sure which factor suits the problem well.
In this situation, the InversionPool
from CoFI can be handy.
lambdas = np.logspace(-6, 6, 15)
my_lcurve_problems = []
for lamb in lambdas:
my_problem = cofi.BaseProblem()
kwargs = {
"fwd": forward_sw,
"periods": synth_d_periods,
"d_obs": d_obs,
"lamda": lamb
}
my_problem.set_objective(my_objective, kwargs=kwargs)
my_problem.set_gradient(my_objective_gradient, kwargs=kwargs)
my_problem.set_hessian(my_objective_hessian, kwargs=kwargs)
my_problem.set_initial_model(init_model)
my_lcurve_problems.append(my_problem)
def my_callback(inv_result, i):
m = inv_result.model
res_norm = np.linalg.norm(forward_sw(m, synth_d_periods) - d_obs)
reg_norm = np.sqrt(my_reg(m))
print(f"Finished inversion with lambda={lambdas[i]}: {res_norm}, {reg_norm}")
return res_norm, reg_norm
my_inversion_pool = cofi.utils.InversionPool(
list_of_inv_problems=my_lcurve_problems,
list_of_inv_options=inv_options_optimiser,
callback=my_callback,
parallel=False
)
all_res, all_cb_returns = my_inversion_pool.run()
l_curve_points = list(zip(*all_cb_returns))
Finished inversion with lambda=1e-06: 0.024553006135234645, 4.99805835268218
Finished inversion with lambda=7.196856730011514e-06: 0.02580846716011747, 2.4911951853445333
Finished inversion with lambda=5.1794746792312125e-05: 0.027008633410123793, 1.2840642724354572
Finished inversion with lambda=0.0003727593720314938: 0.02762718792392687, 1.1669353971336833
Finished inversion with lambda=0.0026826957952797246: 0.0286667339637953, 1.1432552848797986
Finished inversion with lambda=0.019306977288832496: 0.04006872346784902, 1.1088903308334361
Finished inversion with lambda=0.1389495494373136: 0.14882281456160756, 0.9734184900709462
Finished inversion with lambda=1.0: 0.4947597385867233, 0.6567054865218048
Finished inversion with lambda=7.196856730011514: 1.0965644431078774, 0.31353590132833054
Finished inversion with lambda=51.79474679231202: 1.6228845583705995, 0.06766337615005368
Finished inversion with lambda=372.7593720314938: 1.7479562697932292, 0.010122391380161093
Finished inversion with lambda=2682.6957952797275: 1.7668611464779829, 0.0014208105468626062
Finished inversion with lambda=19306.977288832455: 1.7695205273135028, 0.0001977765631969541
Finished inversion with lambda=138949.5494373136: 1.7698955895615756, 2.7484668777127396e-05
Finished inversion with lambda=1000000.0: 1.7699472844137434, 3.819054748877029e-06
# print all the lambdas
lambdas
array([1.00000000e-06, 7.19685673e-06, 5.17947468e-05, 3.72759372e-04,
2.68269580e-03, 1.93069773e-02, 1.38949549e-01, 1.00000000e+00,
7.19685673e+00, 5.17947468e+01, 3.72759372e+02, 2.68269580e+03,
1.93069773e+04, 1.38949549e+05, 1.00000000e+06])
Plot L-curve
# plot the L-curve
res_norm, reg_norm = l_curve_points
plt.plot(reg_norm, res_norm, '.-')
plt.xlabel(r'Norm of regularization term $||Wm||_2$')
plt.ylabel(r'Norm of residual $||g(m)-d||_2$')
for i in range(0, len(lambdas), 2):
plt.annotate(f'{lambdas[i]:.1e}', (reg_norm[i], res_norm[i]), fontsize=8)
Optimisation with damping#
From the L-curve plot above, it seems that a damping factor of around 0.02 would be good.
lamda = 0.02
kwargs = {
"fwd": forward_sw,
"periods": synth_d_periods,
"d_obs": d_obs,
"lamda": lamda
}
sw_problem = cofi.BaseProblem()
sw_problem.set_objective(my_objective, kwargs=kwargs)
sw_problem.set_gradient(my_objective_gradient, kwargs=kwargs)
sw_problem.set_hessian(my_objective_hessian, kwargs=kwargs)
sw_problem.set_initial_model(init_model)
Define ``Inversion`` and run
inv_optimiser = cofi.Inversion(sw_problem, inv_options_optimiser)
inv_result_optimiser = inv_optimiser.run()
Plot results
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from true model", color_d_pred="orange", axes=axes)
# plot the model and d_pred for damped solution, and d_obs
plot_model_and_data(model=inv_result_optimiser.model, label_model="damped solution", color_model="purple",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from damped solution", color_d_pred="purple", axes=axes);
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=axes[1], scatter=True, color="red", s=20, label="d_obs")
axes[1].legend();
<matplotlib.legend.Legend object at 0x7fd0a8115cd0>
Fixed-dimensional sampling#
Prepare ``BaseProblem`` for fixed-dimensional sampling
thick_min = 5
thick_max = 30
vs_min = 2
vs_max = 5
def my_log_prior(model):
thicknesses, vs = split_layercake_model(model)
thicknesses_out_of_bounds = (thicknesses < thick_min) | (thicknesses > thick_max)
vs_out_of_bounds = (vs < vs_min) | (vs > vs_max)
if np.any(thicknesses_out_of_bounds) or np.any(vs_out_of_bounds):
return float("-inf")
log_prior = -np.log(thick_max - thick_min) * len(thicknesses) - np.log(vs_max - vs_min) * len(vs)
return log_prior
Cdinv = np.eye(len(d_obs))/(noise_level**2) # inverse data covariance matrix
def my_log_likelihood(model):
try:
d_pred = forward_sw(model, synth_d_periods)
except:
return float("-inf")
residual = d_obs - d_pred
return -0.5 * residual @ (Cdinv @ residual).T
n_walkers = 40
my_walkers_start = np.ones((n_walkers, n_dims)) * inv_result_optimiser.model
for i in range(n_walkers):
my_walkers_start[i,:] += np.random.normal(0, 0.3, n_dims)
sw_problem.set_log_prior(my_log_prior)
sw_problem.set_log_likelihood(my_log_likelihood)
Define ``InversionOptions``
inv_options_fixed_d_sampling = cofi.InversionOptions()
inv_options_fixed_d_sampling.set_tool("emcee")
inv_options_fixed_d_sampling.set_params(
nwalkers=n_walkers,
nsteps=2_000,
initial_state=my_walkers_start,
skip_initial_state_check=True,
progress=True
)
Define ``Inversion`` and run
We will disable the display of warnings temporarily due to the
unavoidable existence of -inf
in our prior.
np.seterr(all="ignore");
{'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}
Sample the prior#
prior_sampling_problem = cofi.BaseProblem()
prior_sampling_problem.set_log_posterior(my_log_prior)
prior_sampling_problem.set_model_shape(init_model.shape)
prior_sampler = cofi.Inversion(prior_sampling_problem, inv_options_fixed_d_sampling)
prior_results = prior_sampler.run()
0%| | 0/2000 [00:00<?, ?it/s]
6%|▌ | 110/2000 [00:00<00:01, 1093.98it/s]
11%|█ | 221/2000 [00:00<00:01, 1099.40it/s]
17%|█▋ | 335/2000 [00:00<00:01, 1114.09it/s]
22%|██▏ | 448/2000 [00:00<00:01, 1119.40it/s]
28%|██▊ | 562/2000 [00:00<00:01, 1123.78it/s]
34%|███▍ | 677/2000 [00:00<00:01, 1130.14it/s]
40%|███▉ | 792/2000 [00:00<00:01, 1134.52it/s]
45%|████▌ | 907/2000 [00:00<00:00, 1138.02it/s]
51%|█████ | 1023/2000 [00:00<00:00, 1143.49it/s]
57%|█████▋ | 1139/2000 [00:01<00:00, 1145.91it/s]
63%|██████▎ | 1256/2000 [00:01<00:00, 1150.52it/s]
69%|██████▊ | 1372/2000 [00:01<00:00, 1152.33it/s]
74%|███████▍ | 1488/2000 [00:01<00:00, 1151.12it/s]
80%|████████ | 1606/2000 [00:01<00:00, 1157.24it/s]
86%|████████▌ | 1723/2000 [00:01<00:00, 1158.45it/s]
92%|█████████▏| 1839/2000 [00:01<00:00, 1157.40it/s]
98%|█████████▊| 1956/2000 [00:01<00:00, 1160.76it/s]
100%|██████████| 2000/2000 [00:01<00:00, 1144.46it/s]
import arviz as az
labels = ["v0", "t0", "v1", "t1", "v2", "t2", "v3", "t3", "v4", "t4", "v5", "t5", "v6", "t6", "v7", "t7", "v8"]
prior_results_sampler = prior_results.sampler
az_idata_prior = az.from_emcee(prior_results_sampler, var_names=labels)
axes = az.plot_trace(
az_idata_prior,
backend_kwargs={"constrained_layout":True},
figsize=(10,20),
)
for i, axes_pair in enumerate(axes):
ax1 = axes_pair[0]
ax2 = axes_pair[1]
ax1.set_xlabel("parameter value")
ax1.set_ylabel("density value")
ax2.set_xlabel("number of iterations")
ax2.set_ylabel("parameter value")
Sample the posterior#
inversion_fixed_d_sampler = cofi.Inversion(sw_problem, inv_options_fixed_d_sampling)
inv_result_fixed_d_sampler = inversion_fixed_d_sampler.run()
0%| | 0/2000 [00:00<?, ?it/s]
0%| | 6/2000 [00:00<00:36, 54.24it/s]
1%| | 12/2000 [00:00<00:38, 51.48it/s]
1%| | 18/2000 [00:00<00:39, 49.84it/s]
1%| | 23/2000 [00:00<00:41, 47.93it/s]
1%|▏ | 28/2000 [00:00<00:40, 48.47it/s]
2%|▏ | 33/2000 [00:00<00:40, 48.67it/s]
2%|▏ | 38/2000 [00:00<00:40, 48.85it/s]
2%|▏ | 43/2000 [00:00<00:40, 48.92it/s]
2%|▏ | 49/2000 [00:00<00:39, 49.59it/s]
3%|▎ | 55/2000 [00:01<00:39, 49.82it/s]
3%|▎ | 61/2000 [00:01<00:38, 50.25it/s]
3%|▎ | 67/2000 [00:01<00:36, 52.40it/s]
4%|▎ | 73/2000 [00:01<00:36, 52.13it/s]
4%|▍ | 79/2000 [00:01<00:36, 53.22it/s]
4%|▍ | 85/2000 [00:01<00:35, 54.39it/s]
5%|▍ | 91/2000 [00:01<00:34, 55.56it/s]
5%|▍ | 97/2000 [00:01<00:34, 55.64it/s]
5%|▌ | 103/2000 [00:01<00:33, 56.56it/s]
5%|▌ | 109/2000 [00:02<00:32, 57.31it/s]
6%|▌ | 115/2000 [00:02<00:32, 57.95it/s]
6%|▌ | 122/2000 [00:02<00:31, 59.57it/s]
6%|▋ | 129/2000 [00:02<00:31, 60.17it/s]
7%|▋ | 136/2000 [00:02<00:29, 62.51it/s]
7%|▋ | 143/2000 [00:02<00:29, 62.73it/s]
8%|▊ | 150/2000 [00:02<00:29, 62.32it/s]
8%|▊ | 157/2000 [00:02<00:29, 63.44it/s]
8%|▊ | 165/2000 [00:02<00:27, 65.93it/s]
9%|▊ | 172/2000 [00:03<00:28, 64.89it/s]
9%|▉ | 179/2000 [00:03<00:27, 65.22it/s]
9%|▉ | 186/2000 [00:03<00:28, 64.71it/s]
10%|▉ | 193/2000 [00:03<00:27, 65.36it/s]
10%|█ | 200/2000 [00:03<00:27, 65.78it/s]
10%|█ | 207/2000 [00:03<00:27, 65.61it/s]
11%|█ | 214/2000 [00:03<00:27, 66.03it/s]
11%|█ | 221/2000 [00:03<00:26, 67.10it/s]
11%|█▏ | 228/2000 [00:03<00:26, 66.84it/s]
12%|█▏ | 236/2000 [00:04<00:26, 67.61it/s]
12%|█▏ | 243/2000 [00:04<00:26, 67.16it/s]
13%|█▎ | 251/2000 [00:04<00:25, 68.99it/s]
13%|█▎ | 259/2000 [00:04<00:24, 70.02it/s]
13%|█▎ | 266/2000 [00:04<00:25, 69.08it/s]
14%|█▎ | 273/2000 [00:04<00:24, 69.24it/s]
14%|█▍ | 281/2000 [00:04<00:24, 69.78it/s]
14%|█▍ | 288/2000 [00:04<00:25, 68.01it/s]
15%|█▍ | 295/2000 [00:04<00:24, 68.52it/s]
15%|█▌ | 303/2000 [00:04<00:24, 70.23it/s]
16%|█▌ | 311/2000 [00:05<00:23, 71.20it/s]
16%|█▌ | 319/2000 [00:05<00:23, 70.43it/s]
16%|█▋ | 327/2000 [00:05<00:23, 70.86it/s]
17%|█▋ | 335/2000 [00:05<00:23, 71.23it/s]
17%|█▋ | 343/2000 [00:05<00:23, 70.04it/s]
18%|█▊ | 351/2000 [00:05<00:23, 70.82it/s]
18%|█▊ | 359/2000 [00:05<00:23, 70.90it/s]
18%|█▊ | 367/2000 [00:05<00:22, 73.29it/s]
19%|█▉ | 376/2000 [00:05<00:21, 75.44it/s]
19%|█▉ | 384/2000 [00:06<00:21, 75.76it/s]
20%|█▉ | 392/2000 [00:06<00:21, 73.93it/s]
20%|██ | 401/2000 [00:06<00:21, 75.54it/s]
20%|██ | 409/2000 [00:06<00:21, 74.27it/s]
21%|██ | 417/2000 [00:06<00:21, 74.89it/s]
21%|██▏ | 426/2000 [00:06<00:20, 76.31it/s]
22%|██▏ | 435/2000 [00:06<00:20, 77.89it/s]
22%|██▏ | 443/2000 [00:06<00:20, 77.65it/s]
23%|██▎ | 452/2000 [00:06<00:19, 78.91it/s]
23%|██▎ | 460/2000 [00:07<00:19, 77.57it/s]
23%|██▎ | 468/2000 [00:07<00:20, 75.16it/s]
24%|██▍ | 476/2000 [00:07<00:20, 75.36it/s]
24%|██▍ | 485/2000 [00:07<00:19, 77.76it/s]
25%|██▍ | 493/2000 [00:07<00:19, 78.01it/s]
25%|██▌ | 502/2000 [00:07<00:18, 79.17it/s]
26%|██▌ | 511/2000 [00:07<00:18, 81.49it/s]
26%|██▌ | 520/2000 [00:07<00:17, 82.63it/s]
26%|██▋ | 529/2000 [00:07<00:17, 83.33it/s]
27%|██▋ | 538/2000 [00:08<00:17, 84.63it/s]
27%|██▋ | 547/2000 [00:08<00:17, 84.95it/s]
28%|██▊ | 556/2000 [00:08<00:17, 82.65it/s]
28%|██▊ | 565/2000 [00:08<00:17, 80.78it/s]
29%|██▊ | 574/2000 [00:08<00:17, 81.16it/s]
29%|██▉ | 583/2000 [00:08<00:17, 81.31it/s]
30%|██▉ | 592/2000 [00:08<00:16, 82.85it/s]
30%|███ | 601/2000 [00:08<00:16, 82.32it/s]
30%|███ | 610/2000 [00:08<00:17, 81.04it/s]
31%|███ | 619/2000 [00:09<00:17, 80.66it/s]
31%|███▏ | 628/2000 [00:09<00:17, 80.38it/s]
32%|███▏ | 637/2000 [00:09<00:17, 79.31it/s]
32%|███▏ | 646/2000 [00:09<00:16, 80.86it/s]
33%|███▎ | 655/2000 [00:09<00:16, 80.91it/s]
33%|███▎ | 664/2000 [00:09<00:16, 81.14it/s]
34%|███▎ | 673/2000 [00:09<00:16, 80.08it/s]
34%|███▍ | 682/2000 [00:09<00:16, 80.20it/s]
35%|███▍ | 691/2000 [00:09<00:16, 81.15it/s]
35%|███▌ | 700/2000 [00:10<00:16, 80.18it/s]
35%|███▌ | 709/2000 [00:10<00:16, 80.09it/s]
36%|███▌ | 718/2000 [00:10<00:16, 75.63it/s]
36%|███▋ | 726/2000 [00:10<00:17, 74.22it/s]
37%|███▋ | 734/2000 [00:10<00:17, 74.18it/s]
37%|███▋ | 742/2000 [00:10<00:16, 75.46it/s]
38%|███▊ | 750/2000 [00:10<00:16, 75.23it/s]
38%|███▊ | 758/2000 [00:10<00:16, 74.65it/s]
38%|███▊ | 766/2000 [00:10<00:16, 75.86it/s]
39%|███▊ | 774/2000 [00:11<00:16, 76.11it/s]
39%|███▉ | 782/2000 [00:11<00:15, 76.90it/s]
40%|███▉ | 790/2000 [00:11<00:15, 76.44it/s]
40%|███▉ | 798/2000 [00:11<00:15, 76.38it/s]
40%|████ | 806/2000 [00:11<00:15, 75.05it/s]
41%|████ | 815/2000 [00:11<00:15, 76.80it/s]
41%|████ | 823/2000 [00:11<00:15, 76.48it/s]
42%|████▏ | 831/2000 [00:11<00:15, 75.14it/s]
42%|████▏ | 839/2000 [00:11<00:15, 75.49it/s]
42%|████▏ | 848/2000 [00:12<00:15, 76.79it/s]
43%|████▎ | 856/2000 [00:12<00:15, 75.02it/s]
43%|████▎ | 865/2000 [00:12<00:14, 77.03it/s]
44%|████▎ | 874/2000 [00:12<00:14, 78.43it/s]
44%|████▍ | 883/2000 [00:12<00:13, 80.33it/s]
45%|████▍ | 892/2000 [00:12<00:14, 78.19it/s]
45%|████▌ | 900/2000 [00:12<00:14, 76.44it/s]
45%|████▌ | 909/2000 [00:12<00:14, 77.42it/s]
46%|████▌ | 917/2000 [00:12<00:13, 77.63it/s]
46%|████▋ | 925/2000 [00:13<00:14, 75.36it/s]
47%|████▋ | 934/2000 [00:13<00:13, 79.32it/s]
47%|████▋ | 943/2000 [00:13<00:13, 80.46it/s]
48%|████▊ | 953/2000 [00:13<00:12, 83.51it/s]
48%|████▊ | 963/2000 [00:13<00:12, 85.98it/s]
49%|████▊ | 973/2000 [00:13<00:11, 88.98it/s]
49%|████▉ | 983/2000 [00:13<00:11, 91.03it/s]
50%|████▉ | 993/2000 [00:13<00:11, 90.56it/s]
50%|█████ | 1003/2000 [00:13<00:11, 88.83it/s]
51%|█████ | 1013/2000 [00:13<00:11, 88.94it/s]
51%|█████ | 1022/2000 [00:14<00:11, 87.88it/s]
52%|█████▏ | 1031/2000 [00:14<00:10, 88.43it/s]
52%|█████▏ | 1041/2000 [00:14<00:10, 89.95it/s]
52%|█████▎ | 1050/2000 [00:14<00:10, 89.05it/s]
53%|█████▎ | 1059/2000 [00:14<00:10, 88.15it/s]
53%|█████▎ | 1068/2000 [00:14<00:10, 85.45it/s]
54%|█████▍ | 1077/2000 [00:14<00:10, 84.84it/s]
54%|█████▍ | 1087/2000 [00:14<00:10, 88.10it/s]
55%|█████▍ | 1096/2000 [00:14<00:10, 87.93it/s]
55%|█████▌ | 1106/2000 [00:15<00:10, 88.94it/s]
56%|█████▌ | 1115/2000 [00:15<00:10, 86.39it/s]
56%|█████▌ | 1124/2000 [00:15<00:10, 87.28it/s]
57%|█████▋ | 1134/2000 [00:15<00:09, 90.14it/s]
57%|█████▋ | 1144/2000 [00:15<00:09, 90.27it/s]
58%|█████▊ | 1154/2000 [00:15<00:09, 90.81it/s]
58%|█████▊ | 1164/2000 [00:15<00:09, 90.63it/s]
59%|█████▊ | 1174/2000 [00:15<00:09, 90.80it/s]
59%|█████▉ | 1184/2000 [00:15<00:09, 89.91it/s]
60%|█████▉ | 1193/2000 [00:16<00:09, 88.64it/s]
60%|██████ | 1203/2000 [00:16<00:08, 91.67it/s]
61%|██████ | 1213/2000 [00:16<00:08, 90.47it/s]
61%|██████ | 1223/2000 [00:16<00:08, 90.66it/s]
62%|██████▏ | 1233/2000 [00:16<00:08, 88.48it/s]
62%|██████▏ | 1243/2000 [00:16<00:08, 90.14it/s]
63%|██████▎ | 1253/2000 [00:16<00:08, 88.79it/s]
63%|██████▎ | 1262/2000 [00:16<00:08, 87.08it/s]
64%|██████▎ | 1271/2000 [00:16<00:08, 85.98it/s]
64%|██████▍ | 1281/2000 [00:17<00:08, 86.99it/s]
64%|██████▍ | 1290/2000 [00:17<00:08, 85.44it/s]
65%|██████▍ | 1299/2000 [00:17<00:08, 84.40it/s]
65%|██████▌ | 1308/2000 [00:17<00:08, 85.69it/s]
66%|██████▌ | 1317/2000 [00:17<00:07, 86.10it/s]
66%|██████▋ | 1326/2000 [00:17<00:07, 86.69it/s]
67%|██████▋ | 1335/2000 [00:17<00:07, 87.10it/s]
67%|██████▋ | 1345/2000 [00:17<00:07, 88.59it/s]
68%|██████▊ | 1354/2000 [00:17<00:07, 88.83it/s]
68%|██████▊ | 1363/2000 [00:17<00:07, 86.27it/s]
69%|██████▊ | 1373/2000 [00:18<00:07, 88.47it/s]
69%|██████▉ | 1383/2000 [00:18<00:06, 90.11it/s]
70%|██████▉ | 1393/2000 [00:18<00:06, 90.83it/s]
70%|███████ | 1403/2000 [00:18<00:06, 90.80it/s]
71%|███████ | 1413/2000 [00:18<00:06, 90.66it/s]
71%|███████ | 1423/2000 [00:18<00:06, 88.33it/s]
72%|███████▏ | 1433/2000 [00:18<00:06, 91.00it/s]
72%|███████▏ | 1443/2000 [00:18<00:06, 89.36it/s]
73%|███████▎ | 1452/2000 [00:18<00:06, 89.25it/s]
73%|███████▎ | 1462/2000 [00:19<00:05, 90.27it/s]
74%|███████▎ | 1472/2000 [00:19<00:05, 92.46it/s]
74%|███████▍ | 1482/2000 [00:19<00:05, 92.25it/s]
75%|███████▍ | 1492/2000 [00:19<00:05, 94.29it/s]
75%|███████▌ | 1502/2000 [00:19<00:05, 94.24it/s]
76%|███████▌ | 1512/2000 [00:19<00:05, 90.75it/s]
76%|███████▌ | 1522/2000 [00:19<00:05, 90.63it/s]
77%|███████▋ | 1532/2000 [00:19<00:05, 90.08it/s]
77%|███████▋ | 1542/2000 [00:19<00:05, 87.32it/s]
78%|███████▊ | 1552/2000 [00:20<00:05, 89.42it/s]
78%|███████▊ | 1561/2000 [00:20<00:04, 89.17it/s]
78%|███████▊ | 1570/2000 [00:20<00:04, 88.48it/s]
79%|███████▉ | 1580/2000 [00:20<00:04, 91.49it/s]
80%|███████▉ | 1590/2000 [00:20<00:04, 93.91it/s]
80%|████████ | 1600/2000 [00:20<00:04, 93.83it/s]
80%|████████ | 1610/2000 [00:20<00:04, 92.49it/s]
81%|████████ | 1620/2000 [00:20<00:04, 91.78it/s]
82%|████████▏ | 1630/2000 [00:20<00:04, 91.40it/s]
82%|████████▏ | 1640/2000 [00:20<00:03, 92.69it/s]
82%|████████▎ | 1650/2000 [00:21<00:03, 92.52it/s]
83%|████████▎ | 1660/2000 [00:21<00:03, 93.87it/s]
84%|████████▎ | 1670/2000 [00:21<00:03, 92.54it/s]
84%|████████▍ | 1680/2000 [00:21<00:03, 93.90it/s]
84%|████████▍ | 1690/2000 [00:21<00:03, 95.04it/s]
85%|████████▌ | 1700/2000 [00:21<00:03, 95.48it/s]
86%|████████▌ | 1710/2000 [00:21<00:03, 92.08it/s]
86%|████████▌ | 1720/2000 [00:21<00:03, 91.86it/s]
86%|████████▋ | 1730/2000 [00:21<00:02, 90.85it/s]
87%|████████▋ | 1740/2000 [00:22<00:02, 91.10it/s]
88%|████████▊ | 1750/2000 [00:22<00:02, 91.60it/s]
88%|████████▊ | 1760/2000 [00:22<00:02, 91.66it/s]
88%|████████▊ | 1770/2000 [00:22<00:02, 92.10it/s]
89%|████████▉ | 1780/2000 [00:22<00:02, 92.53it/s]
90%|████████▉ | 1790/2000 [00:22<00:02, 91.77it/s]
90%|█████████ | 1800/2000 [00:22<00:02, 91.64it/s]
90%|█████████ | 1810/2000 [00:22<00:02, 93.29it/s]
91%|█████████ | 1820/2000 [00:22<00:01, 90.77it/s]
92%|█████████▏| 1830/2000 [00:23<00:01, 91.63it/s]
92%|█████████▏| 1840/2000 [00:23<00:01, 92.17it/s]
93%|█████████▎| 1851/2000 [00:23<00:01, 95.04it/s]
93%|█████████▎| 1861/2000 [00:23<00:01, 94.69it/s]
94%|█████████▎| 1871/2000 [00:23<00:01, 93.22it/s]
94%|█████████▍| 1881/2000 [00:23<00:01, 91.52it/s]
95%|█████████▍| 1891/2000 [00:23<00:01, 90.68it/s]
95%|█████████▌| 1901/2000 [00:23<00:01, 92.39it/s]
96%|█████████▌| 1911/2000 [00:23<00:00, 89.69it/s]
96%|█████████▌| 1921/2000 [00:24<00:00, 90.79it/s]
97%|█████████▋| 1931/2000 [00:24<00:00, 91.76it/s]
97%|█████████▋| 1941/2000 [00:24<00:00, 93.58it/s]
98%|█████████▊| 1951/2000 [00:24<00:00, 94.35it/s]
98%|█████████▊| 1961/2000 [00:24<00:00, 94.72it/s]
99%|█████████▊| 1971/2000 [00:24<00:00, 92.06it/s]
99%|█████████▉| 1981/2000 [00:24<00:00, 90.92it/s]
100%|█████████▉| 1991/2000 [00:24<00:00, 91.74it/s]
100%|██████████| 2000/2000 [00:24<00:00, 80.36it/s]
sampler = inv_result_fixed_d_sampler.sampler
az_idata = az.from_emcee(sampler, var_names=labels)
az_idata.get("posterior")
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="initial model for damped solution", color_model="black",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from initial model for damped solution", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from true model", color_d_pred="orange", axes=axes)
# plot the model and d_pred for damped solution, and d_obs
plot_model_and_data(model=inv_result_optimiser.model, label_model="damped solution", color_model="green",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from damped solution", color_d_pred="green", axes=axes);
# plot randomly selected samples and data predictions from samples
flat_samples = sampler.get_chain(discard=500, thin=500, flat=True)
rand_indices = np.random.randint(len(flat_samples), size=100)
for idx in rand_indices:
sample = flat_samples[idx]
label_model = "sample models" if idx == 0 else None
label_d_pred = "d_pred from samples" if idx == 0 else None
plot_model_and_data(model=sample, label_model=label_model, color_model="gray",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred=label_d_pred, color_d_pred="gray", axes=axes, light_thin=True)
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=axes[1], scatter=True, color="red", s=20, label="d_obs")
axes[0].set_ylim(170)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd0a9095cd0>
axes = az.plot_trace(
az_idata,
backend_kwargs={"constrained_layout":True},
figsize=(10,20)
)
for i, axes_pair in enumerate(axes):
ax1 = axes_pair[0]
ax2 = axes_pair[1]
ax1.axvline(true_model[i], linestyle='dotted', color='red')
ax1.set_xlabel("parameter value")
ax1.set_ylabel("density value")
ax2.set_xlabel("number of iterations")
ax2.set_ylabel("parameter value")
More steps?
Due to time restrictions, we have only run 2_000 steps above, which might be enough for illustration purpose and sanity check, but are not enough for an actual inversion.
On a seperate experiment, we ran 200_000 steps instead and produced the following samples plot.
Trans-dimensional sampling#
Prepare utilities for trans-dimensional sampling
def forward_for_bayesbay(state):
vs = state["voronoi"]["vs"]
voronoi_sites = state["voronoi"]["discretization"]
depths = (voronoi_sites[:-1] + voronoi_sites[1:]) / 2
thicknesses = depths - np.insert(depths[:-1], 0, 0)
model = form_layercake_model(thicknesses, vs)
return forward_sw(model, synth_d_periods)
targets = [bayesbay.Target("rayleigh", d_obs, covariance_mat_inv=1/noise_level**2)]
fwd_funcs = [forward_for_bayesbay]
my_log_likelihood = bayesbay.LogLikelihood(targets, fwd_funcs)
param_vs = bayesbay.prior.UniformPrior(
name="vs",
vmin=[2.7, 3.2, 3.75],
vmax=[4, 4.75, 5],
position=[0, 40, 80],
perturb_std=0.15
)
def param_vs_initialize(param, positions):
vmin, vmax = param.get_vmin_vmax(positions)
sorted_vals = np.sort(np.random.uniform(vmin, vmax, positions.size))
for i in range (len(sorted_vals)):
val = sorted_vals[i]
vmin_i = vmin if np.isscalar(vmin) else vmin[i]
vmax_i = vmax if np.isscalar(vmax) else vmax[i]
if val < vmin_i or val > vmax_i:
if val > vmax_i: sorted_vals[i] = vmax_i
if val < vmin_i: sorted_vals[i] = vmin_i
return sorted_vals
param_vs.set_custom_initialize(param_vs_initialize)
parameterization = bayesbay.parameterization.Parameterization(
bayesbay.discretization.Voronoi1D(
name="voronoi",
vmin=0,
vmax=150,
perturb_std=10,
n_dimensions=None,
n_dimensions_min=4,
n_dimensions_max=15,
parameters=[param_vs],
)
)
my_perturbation_funcs = parameterization.perturbation_functions
n_chains=12
walkers_start = []
for i in range(n_chains):
walkers_start.append(parameterization.initialize())
Define ``InversionOptions``
inv_options_trans_d_sampling = cofi.InversionOptions()
inv_options_trans_d_sampling.set_tool("bayesbay")
inv_options_trans_d_sampling.set_params(
walkers_starting_states=walkers_start,
perturbation_funcs=my_perturbation_funcs,
log_like_ratio_func=my_log_likelihood,
n_chains=n_chains,
n_iterations=3_000,
burnin_iterations=1_000,
verbose=False,
save_every=200,
)
Define ``Inversion`` and run
inversion_trans_d_sampler = cofi.Inversion(sw_problem, inv_options_trans_d_sampling)
inv_result_trans_d_sampler = inversion_trans_d_sampler.run()
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="initial model for damped solution", color_model="black",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from initial model for damped solution", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=true_model, label_model="true model", color_model="orange",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from true model", color_d_pred="orange", axes=axes)
# plot the model and d_pred for damped solution, and d_obs
plot_model_and_data(model=inv_result_optimiser.model, label_model="damped solution", color_model="green",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred="d_pred from damped solution", color_d_pred="green", axes=axes);
# plot randomly selected samples and data predictions from samples
for i, sample in enumerate(samples):
label_model = "sample models" if i == 0 else None
label_d_pred = "d_pred from samples" if i == 0 else None
plot_model_and_data(model=sample, label_model=label_model, color_model="gray",
forward_func=forward_sw, periods=synth_d_periods,
label_d_pred=label_d_pred, color_d_pred="gray", axes=axes, light_thin=True)
# plot d_obs
plot_data(d_obs, synth_d_periods, ax=axes[1], scatter=True, color="red", s=20, label="d_obs")
axes[0].set_ylim(170)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd245d45a10>
Field data example#
Read data#
Rayleigh observations
file_surf_data = "../../data/sw_rf_joint/data/SURF/nnall.dsp"
with open(file_surf_data, "r") as file:
lines = file.readlines()
surf_data = []
for line in lines:
row = line.strip().split()
if "C" in row:
surf_data.append([float(e) for e in row[5:8]])
field_d = np.array(surf_data)
field_d_periods = field_d[:,0]
field_d_obs = field_d[:,1]
ax = plot_data(field_d_obs, field_d_periods, color="brown", s=5, scatter=True,
label="d_obs")
ax.legend();
<matplotlib.legend.Legend object at 0x7fd25f7d5ed0>
Reference good model
file_end_mod = "../../data/sw_rf_joint/data/SURF/end.mod"
with open(file_end_mod, "r") as file:
lines = file.readlines()
ref_good_model = []
for line in lines[12:]:
row = line.strip().split()
ref_good_model.append([float(row[0]), float(row[2])])
ref_good_model = np.array(ref_good_model)
ref_good_model = form_layercake_model(ref_good_model[:-1,0], ref_good_model[:,1])
_, ax = plt.subplots(figsize=(4,6))
plot_model(ref_good_model, ax=ax, alpha=1);
<Axes: title={'center': 'model'}, xlabel='Vs (km/s)', ylabel='Depth (km)'>
Modified forward utility#
def forward_sw_interp(model, periods=field_d_periods):
pysurf_periods = np.logspace(
np.log(np.min(periods)),
np.log(np.max(periods+1)),
60,
base=np.e,
)
pysurf_dpred = forward_sw(model, pysurf_periods)
interp_func = scipy.interpolate.interp1d(pysurf_periods,
pysurf_dpred,
fill_value="extrapolate")
dpred = interp_func(periods)
return dpred
Optimisation#
n_dims = 29
init_thicknesses = np.ones((n_dims//2,)) * 10
init_vs = np.ones((n_dims//2+1,)) * 4.0
init_model = form_layercake_model(init_thicknesses, init_vs)
my_reg = cofi.utils.QuadraticReg(
weighting_matrix="damping",
model_shape=(n_dims,),
reference_model=init_model
)
Optimisation with no damping#
lamda = 0
kwargs = {
"fwd": forward_sw_interp,
"periods": field_d_periods,
"d_obs": field_d_obs,
"lamda": lamda,
}
sw_field_problem_no_reg = cofi.BaseProblem()
sw_field_problem_no_reg.set_objective(my_objective, kwargs=kwargs)
sw_field_problem_no_reg.set_gradient(my_objective_gradient, kwargs=kwargs)
sw_field_problem_no_reg.set_hessian(my_objective_hessian, kwargs=kwargs)
sw_field_problem_no_reg.set_initial_model(init_model)
Define ``Inversion`` and run
inv_sw_field_problem_no_reg = cofi.Inversion(sw_field_problem_no_reg, inv_options_optimiser)
inv_result_sw_field_no_reg = inv_sw_field_problem_no_reg.run()
Plot results
field_d_periods_logspace = np.logspace(
np.log(np.min(field_d_periods)),
np.log(np.max(field_d_periods+1)),
60,
base=np.e,
)
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=ref_good_model, label_model="reference good model", color_model="red",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from reference good model", color_d_pred="red", axes=axes)
# plot the model and d_pred for inverted model, and d_obs
plot_model_and_data(model=inv_result_sw_field_no_reg.model,
label_model="inverted model from field data", color_model="purple",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from inverted model", color_d_pred="purple", axes=axes)
# plot d_obs
plot_data(field_d_obs, field_d_periods, ax=axes[1], scatter=True, color="orange", s=8, label="d_obs")
axes[0].set_ylim(100, 0)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.4))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd245b278d0>
Optimal damping#
Again, we would like to find a good regularisation factor.
lambdas = np.logspace(-6, 6, 15)
my_lcurve_problems = []
for lamb in lambdas:
my_problem = cofi.BaseProblem()
kwargs = {
"fwd": forward_sw_interp,
"periods": field_d_periods,
"d_obs": field_d_obs,
"lamda": lamb,
}
my_problem.set_objective(my_objective, kwargs=kwargs)
my_problem.set_gradient(my_objective_gradient, kwargs=kwargs)
my_problem.set_hessian(my_objective_hessian, kwargs=kwargs)
my_problem.set_initial_model(init_model)
my_lcurve_problems.append(my_problem)
def my_callback(inv_result, i):
m = inv_result.model
res_norm = np.linalg.norm(forward_sw_interp(m, field_d_periods) - field_d_obs)
reg_norm = np.sqrt(my_reg(m))
print(f"Finished inversion with lambda={lambdas[i]}: {res_norm}, {reg_norm}")
return res_norm, reg_norm
my_inversion_pool = cofi.utils.InversionPool(
list_of_inv_problems=my_lcurve_problems,
list_of_inv_options=inv_options_optimiser,
callback=my_callback,
parallel=False
)
all_res, all_cb_returns = my_inversion_pool.run()
l_curve_points = list(zip(*all_cb_returns))
Finished inversion with lambda=1e-06: 1.9540941311396671, 26.760380619787956
Finished inversion with lambda=7.196856730011514e-06: 1.9548537779696775, 23.084178681310398
Finished inversion with lambda=5.1794746792312125e-05: 1.9672756794905297, 10.950500473754316
Finished inversion with lambda=0.0003727593720314938: 1.9699341235211631, 7.634041352559792
Finished inversion with lambda=0.0026826957952797246: 1.9782390541679031, 4.552509100476203
Finished inversion with lambda=0.019306977288832496: 2.0050549438091747, 2.3442273803041136
Finished inversion with lambda=0.1389495494373136: 2.0393073369018655, 1.6477206878151607
Finished inversion with lambda=1.0: 2.112939266124699, 1.3870331002558811
Finished inversion with lambda=7.196856730011514: 2.7878693578372693, 0.9907601514482579
Finished inversion with lambda=51.79474679231202: 4.890126438918003, 0.34475194170977674
Finished inversion with lambda=372.7593720314938: 5.957321022746526, 0.06129962536156985
Finished inversion with lambda=2682.6957952797275: 6.160087164630214, 0.008874921981364005
Finished inversion with lambda=19306.977288832455: 6.189744923132511, 0.001240946449950785
Finished inversion with lambda=138949.5494373136: 6.193898179384247, 0.0001725411516554573
Finished inversion with lambda=1000000.0: 6.194457488485488, 2.3974628324356084e-05
# print all the lambdas
lambdas
array([1.00000000e-06, 7.19685673e-06, 5.17947468e-05, 3.72759372e-04,
2.68269580e-03, 1.93069773e-02, 1.38949549e-01, 1.00000000e+00,
7.19685673e+00, 5.17947468e+01, 3.72759372e+02, 2.68269580e+03,
1.93069773e+04, 1.38949549e+05, 1.00000000e+06])
# plot the L-curve
res_norm, reg_norm = l_curve_points
plt.plot(reg_norm, res_norm, '.-')
plt.xlabel(r'Norm of regularization term $||Wm||_2$')
plt.ylabel(r'Norm of residual $||g(m)-d||_2$')
for i in range(0, len(lambdas), 2):
plt.annotate(f'{lambdas[i]:.1e}', (reg_norm[i], res_norm[i]), fontsize=8)
Optimisation with damping#
lamda = 0.14
kwargs = {
"fwd": forward_sw_interp,
"periods": field_d_periods,
"d_obs": field_d_obs,
"lamda": lamda,
}
sw_field_problem = cofi.BaseProblem()
sw_field_problem.set_objective(my_objective, kwargs=kwargs)
sw_field_problem.set_gradient(my_objective_gradient, kwargs=kwargs)
sw_field_problem.set_hessian(my_objective_hessian, kwargs=kwargs)
sw_field_problem.set_initial_model(init_model)
Define ``Inversion`` and run
inv_sw_field_problem = cofi.Inversion(sw_field_problem, inv_options_optimiser)
inv_result_sw_field = inv_sw_field_problem.run()
Plot results
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=ref_good_model, label_model="reference good model", color_model="red",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from reference good model", color_d_pred="red", axes=axes)
# plot the model and d_pred for inverted model, and d_obs
plot_model_and_data(model=inv_result_sw_field.model,
label_model="inverted model from field data", color_model="purple",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from inverted model", color_d_pred="purple", axes=axes)
# plot d_obs
plot_data(field_d_obs, field_d_periods, ax=axes[1], scatter=True, color="orange", s=8, label="d_obs")
axes[0].set_ylim(100, 0)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.4))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd25f6f6ed0>
Fixed-dimensional sampling#
We are going to use the same sets of log prior, and we will rewrite the log likelihood function to apply on the field data.
thick_min = 3
thick_max = 10
vs_min = 2
vs_max = 5.5
def my_log_prior(model):
thicknesses, vs = split_layercake_model(model)
thicknesses_out_of_bounds = (thicknesses < thick_min) | (thicknesses > thick_max)
vs_out_of_bounds = (vs < vs_min) | (vs > vs_max)
if np.any(thicknesses_out_of_bounds) or np.any(vs_out_of_bounds):
return float("-inf")
log_prior = - np.log(thick_max - thick_min) * len(thicknesses) \
- np.log(vs_max - vs_min) * len(vs)
return log_prior
# estimate the data noise
d_pred_from_optimiser = forward_sw_interp(inv_result_sw_field.model, field_d_periods)
noise_level = np.std(field_d_obs - d_pred_from_optimiser)
Cdinv = np.eye(len(field_d_obs))/(noise_level**2)
print(f"Estimated noise level: {noise_level}")
Estimated noise level: 0.10587785944399027
def my_log_likelihood(model):
try:
d_pred = forward_sw_interp(model, field_d_periods)
except:
return float("-inf")
residual = field_d_obs - d_pred
return -0.5 * residual @ (Cdinv @ residual).T
n_walkers = 60
my_walkers_start = np.ones((n_walkers, n_dims)) * inv_result_sw_field.model
for i in range(n_walkers):
my_walkers_start[i,:] += np.random.normal(0, 0.3, n_dims)
sw_field_problem.set_log_prior(my_log_prior)
sw_field_problem.set_log_likelihood(my_log_likelihood)
Define ``InversionOptions``
inv_options_fixed_d_sampling = cofi.InversionOptions()
inv_options_fixed_d_sampling.set_tool("emcee")
inv_options_fixed_d_sampling.set_params(
nwalkers=n_walkers,
nsteps=20_000,
initial_state=my_walkers_start,
skip_initial_state_check=True,
progress=True
)
Sample the posterior#
inversion_fixed_d_sampler_field = cofi.Inversion(sw_field_problem,
inv_options_fixed_d_sampling)
inv_result_fixed_d_sampler_field = inversion_fixed_d_sampler_field.run()
0%| | 0/20000 [00:00<?, ?it/s]
0%| | 92/20000 [00:00<00:21, 914.29it/s]
1%| | 185/20000 [00:00<00:21, 918.70it/s]
1%|▏ | 277/20000 [00:00<00:21, 917.00it/s]
2%|▏ | 370/20000 [00:00<00:21, 919.11it/s]
2%|▏ | 462/20000 [00:00<00:21, 913.80it/s]
3%|▎ | 554/20000 [00:00<00:21, 915.57it/s]
3%|▎ | 646/20000 [00:00<00:21, 908.01it/s]
4%|▎ | 738/20000 [00:00<00:21, 911.56it/s]
4%|▍ | 830/20000 [00:00<00:20, 913.42it/s]
5%|▍ | 923/20000 [00:01<00:20, 916.00it/s]
5%|▌ | 1015/20000 [00:01<00:20, 916.90it/s]
6%|▌ | 1107/20000 [00:01<00:20, 913.38it/s]
6%|▌ | 1199/20000 [00:01<00:20, 912.21it/s]
6%|▋ | 1292/20000 [00:01<00:20, 914.73it/s]
7%|▋ | 1384/20000 [00:01<00:20, 915.09it/s]
7%|▋ | 1476/20000 [00:01<00:20, 914.98it/s]
8%|▊ | 1568/20000 [00:01<00:20, 915.52it/s]
8%|▊ | 1660/20000 [00:01<00:20, 913.92it/s]
9%|▉ | 1752/20000 [00:01<00:19, 912.73it/s]
9%|▉ | 1844/20000 [00:02<00:19, 913.30it/s]
10%|▉ | 1936/20000 [00:02<00:19, 912.39it/s]
10%|█ | 2028/20000 [00:02<00:19, 908.79it/s]
11%|█ | 2120/20000 [00:02<00:19, 909.94it/s]
11%|█ | 2211/20000 [00:02<00:19, 908.03it/s]
12%|█▏ | 2303/20000 [00:02<00:19, 911.11it/s]
12%|█▏ | 2395/20000 [00:02<00:19, 910.93it/s]
12%|█▏ | 2487/20000 [00:02<00:19, 908.81it/s]
13%|█▎ | 2578/20000 [00:02<00:19, 908.70it/s]
13%|█▎ | 2670/20000 [00:02<00:19, 911.03it/s]
14%|█▍ | 2762/20000 [00:03<00:18, 909.54it/s]
14%|█▍ | 2854/20000 [00:03<00:18, 911.38it/s]
15%|█▍ | 2946/20000 [00:03<00:18, 902.34it/s]
15%|█▌ | 3037/20000 [00:03<00:18, 904.04it/s]
16%|█▌ | 3130/20000 [00:03<00:18, 909.01it/s]
16%|█▌ | 3221/20000 [00:03<00:18, 908.83it/s]
17%|█▋ | 3312/20000 [00:03<00:18, 904.98it/s]
17%|█▋ | 3403/20000 [00:03<00:18, 902.52it/s]
17%|█▋ | 3495/20000 [00:03<00:18, 904.86it/s]
18%|█▊ | 3587/20000 [00:03<00:18, 908.59it/s]
18%|█▊ | 3680/20000 [00:04<00:17, 912.24it/s]
19%|█▉ | 3772/20000 [00:04<00:17, 914.34it/s]
19%|█▉ | 3864/20000 [00:04<00:17, 915.93it/s]
20%|█▉ | 3956/20000 [00:04<00:17, 915.18it/s]
20%|██ | 4049/20000 [00:04<00:17, 917.05it/s]
21%|██ | 4141/20000 [00:04<00:17, 917.04it/s]
21%|██ | 4233/20000 [00:04<00:17, 916.25it/s]
22%|██▏ | 4325/20000 [00:04<00:17, 916.52it/s]
22%|██▏ | 4417/20000 [00:04<00:16, 917.36it/s]
23%|██▎ | 4510/20000 [00:04<00:16, 918.50it/s]
23%|██▎ | 4603/20000 [00:05<00:16, 919.29it/s]
23%|██▎ | 4695/20000 [00:05<00:16, 918.99it/s]
24%|██▍ | 4787/20000 [00:05<00:16, 915.33it/s]
24%|██▍ | 4879/20000 [00:05<00:16, 908.22it/s]
25%|██▍ | 4972/20000 [00:05<00:16, 912.08it/s]
25%|██▌ | 5064/20000 [00:05<00:16, 912.65it/s]
26%|██▌ | 5156/20000 [00:05<00:16, 913.08it/s]
26%|██▌ | 5248/20000 [00:05<00:16, 914.59it/s]
27%|██▋ | 5340/20000 [00:05<00:16, 915.81it/s]
27%|██▋ | 5432/20000 [00:05<00:15, 914.26it/s]
28%|██▊ | 5524/20000 [00:06<00:15, 910.87it/s]
28%|██▊ | 5616/20000 [00:06<00:15, 912.40it/s]
29%|██▊ | 5708/20000 [00:06<00:15, 912.00it/s]
29%|██▉ | 5800/20000 [00:06<00:15, 912.95it/s]
29%|██▉ | 5893/20000 [00:06<00:15, 915.52it/s]
30%|██▉ | 5986/20000 [00:06<00:15, 916.99it/s]
30%|███ | 6078/20000 [00:06<00:15, 916.37it/s]
31%|███ | 6170/20000 [00:06<00:15, 915.07it/s]
31%|███▏ | 6262/20000 [00:06<00:15, 910.49it/s]
32%|███▏ | 6354/20000 [00:06<00:14, 910.29it/s]
32%|███▏ | 6446/20000 [00:07<00:14, 913.12it/s]
33%|███▎ | 6539/20000 [00:07<00:14, 915.30it/s]
33%|███▎ | 6631/20000 [00:07<00:14, 909.49it/s]
34%|███▎ | 6722/20000 [00:07<00:14, 909.25it/s]
34%|███▍ | 6813/20000 [00:07<00:14, 908.04it/s]
35%|███▍ | 6905/20000 [00:07<00:14, 910.35it/s]
35%|███▍ | 6997/20000 [00:07<00:14, 912.50it/s]
35%|███▌ | 7089/20000 [00:07<00:14, 913.47it/s]
36%|███▌ | 7181/20000 [00:07<00:14, 913.43it/s]
36%|███▋ | 7273/20000 [00:07<00:13, 914.40it/s]
37%|███▋ | 7365/20000 [00:08<00:13, 910.38it/s]
37%|███▋ | 7457/20000 [00:08<00:13, 911.91it/s]
38%|███▊ | 7549/20000 [00:08<00:13, 908.11it/s]
38%|███▊ | 7640/20000 [00:08<00:13, 906.23it/s]
39%|███▊ | 7732/20000 [00:08<00:13, 909.39it/s]
39%|███▉ | 7823/20000 [00:08<00:13, 909.32it/s]
40%|███▉ | 7915/20000 [00:08<00:13, 910.90it/s]
40%|████ | 8007/20000 [00:08<00:13, 912.94it/s]
40%|████ | 8099/20000 [00:08<00:13, 905.25it/s]
41%|████ | 8191/20000 [00:08<00:13, 907.06it/s]
41%|████▏ | 8284/20000 [00:09<00:12, 911.34it/s]
42%|████▏ | 8376/20000 [00:09<00:12, 911.07it/s]
42%|████▏ | 8468/20000 [00:09<00:12, 910.22it/s]
43%|████▎ | 8560/20000 [00:09<00:12, 910.55it/s]
43%|████▎ | 8652/20000 [00:09<00:12, 912.44it/s]
44%|████▎ | 8744/20000 [00:09<00:12, 912.09it/s]
44%|████▍ | 8836/20000 [00:09<00:12, 912.37it/s]
45%|████▍ | 8928/20000 [00:09<00:12, 913.26it/s]
45%|████▌ | 9020/20000 [00:09<00:12, 913.47it/s]
46%|████▌ | 9112/20000 [00:09<00:11, 909.15it/s]
46%|████▌ | 9203/20000 [00:10<00:11, 904.81it/s]
46%|████▋ | 9295/20000 [00:10<00:11, 906.88it/s]
47%|████▋ | 9387/20000 [00:10<00:11, 909.84it/s]
47%|████▋ | 9479/20000 [00:10<00:11, 911.84it/s]
48%|████▊ | 9571/20000 [00:10<00:11, 912.37it/s]
48%|████▊ | 9663/20000 [00:10<00:11, 914.43it/s]
49%|████▉ | 9755/20000 [00:10<00:11, 915.91it/s]
49%|████▉ | 9847/20000 [00:10<00:11, 915.65it/s]
50%|████▉ | 9939/20000 [00:10<00:10, 915.40it/s]
50%|█████ | 10032/20000 [00:10<00:10, 917.14it/s]
51%|█████ | 10125/20000 [00:11<00:10, 918.33it/s]
51%|█████ | 10217/20000 [00:11<00:10, 915.95it/s]
52%|█████▏ | 10309/20000 [00:11<00:10, 913.62it/s]
52%|█████▏ | 10401/20000 [00:11<00:10, 914.54it/s]
52%|█████▏ | 10493/20000 [00:11<00:10, 915.82it/s]
53%|█████▎ | 10585/20000 [00:11<00:10, 913.20it/s]
53%|█████▎ | 10677/20000 [00:11<00:10, 914.90it/s]
54%|█████▍ | 10769/20000 [00:11<00:10, 914.17it/s]
54%|█████▍ | 10861/20000 [00:11<00:09, 915.54it/s]
55%|█████▍ | 10953/20000 [00:12<00:09, 915.40it/s]
55%|█████▌ | 11045/20000 [00:12<00:09, 915.32it/s]
56%|█████▌ | 11138/20000 [00:12<00:09, 916.87it/s]
56%|█████▌ | 11230/20000 [00:12<00:09, 916.68it/s]
57%|█████▋ | 11322/20000 [00:12<00:09, 917.67it/s]
57%|█████▋ | 11414/20000 [00:12<00:09, 917.27it/s]
58%|█████▊ | 11506/20000 [00:12<00:09, 918.03it/s]
58%|█████▊ | 11598/20000 [00:12<00:09, 918.10it/s]
58%|█████▊ | 11690/20000 [00:12<00:09, 918.38it/s]
59%|█████▉ | 11783/20000 [00:12<00:08, 919.38it/s]
59%|█████▉ | 11875/20000 [00:13<00:08, 917.64it/s]
60%|█████▉ | 11967/20000 [00:13<00:08, 917.96it/s]
60%|██████ | 12059/20000 [00:13<00:08, 916.18it/s]
61%|██████ | 12151/20000 [00:13<00:08, 913.08it/s]
61%|██████ | 12243/20000 [00:13<00:08, 915.14it/s]
62%|██████▏ | 12335/20000 [00:13<00:08, 915.04it/s]
62%|██████▏ | 12427/20000 [00:13<00:08, 915.47it/s]
63%|██████▎ | 12519/20000 [00:13<00:08, 915.95it/s]
63%|██████▎ | 12611/20000 [00:13<00:08, 915.47it/s]
64%|██████▎ | 12703/20000 [00:13<00:07, 916.80it/s]
64%|██████▍ | 12795/20000 [00:14<00:07, 915.46it/s]
64%|██████▍ | 12887/20000 [00:14<00:07, 914.40it/s]
65%|██████▍ | 12979/20000 [00:14<00:07, 914.41it/s]
65%|██████▌ | 13071/20000 [00:14<00:07, 912.66it/s]
66%|██████▌ | 13163/20000 [00:14<00:07, 911.21it/s]
66%|██████▋ | 13255/20000 [00:14<00:07, 905.98it/s]
67%|██████▋ | 13346/20000 [00:14<00:07, 901.85it/s]
67%|██████▋ | 13437/20000 [00:14<00:07, 896.65it/s]
68%|██████▊ | 13527/20000 [00:14<00:07, 896.56it/s]
68%|██████▊ | 13618/20000 [00:14<00:07, 899.62it/s]
69%|██████▊ | 13710/20000 [00:15<00:06, 905.07it/s]
69%|██████▉ | 13802/20000 [00:15<00:06, 909.25it/s]
69%|██████▉ | 13893/20000 [00:15<00:06, 900.41it/s]
70%|██████▉ | 13984/20000 [00:15<00:06, 901.15it/s]
70%|███████ | 14076/20000 [00:15<00:06, 904.36it/s]
71%|███████ | 14168/20000 [00:15<00:06, 907.99it/s]
71%|███████▏ | 14260/20000 [00:15<00:06, 910.32it/s]
72%|███████▏ | 14352/20000 [00:15<00:06, 912.28it/s]
72%|███████▏ | 14445/20000 [00:15<00:06, 914.83it/s]
73%|███████▎ | 14537/20000 [00:15<00:05, 915.91it/s]
73%|███████▎ | 14629/20000 [00:16<00:05, 915.82it/s]
74%|███████▎ | 14721/20000 [00:16<00:05, 913.23it/s]
74%|███████▍ | 14814/20000 [00:16<00:05, 915.52it/s]
75%|███████▍ | 14906/20000 [00:16<00:05, 912.88it/s]
75%|███████▍ | 14999/20000 [00:16<00:05, 915.24it/s]
75%|███████▌ | 15091/20000 [00:16<00:05, 915.43it/s]
76%|███████▌ | 15183/20000 [00:16<00:05, 916.45it/s]
76%|███████▋ | 15275/20000 [00:16<00:05, 917.33it/s]
77%|███████▋ | 15367/20000 [00:16<00:05, 915.35it/s]
77%|███████▋ | 15460/20000 [00:16<00:04, 916.87it/s]
78%|███████▊ | 15553/20000 [00:17<00:04, 917.92it/s]
78%|███████▊ | 15646/20000 [00:17<00:04, 918.73it/s]
79%|███████▊ | 15739/20000 [00:17<00:04, 919.13it/s]
79%|███████▉ | 15831/20000 [00:17<00:04, 913.14it/s]
80%|███████▉ | 15924/20000 [00:17<00:04, 915.53it/s]
80%|████████ | 16016/20000 [00:17<00:04, 916.71it/s]
81%|████████ | 16109/20000 [00:17<00:04, 917.68it/s]
81%|████████ | 16201/20000 [00:17<00:04, 917.68it/s]
81%|████████▏ | 16293/20000 [00:17<00:04, 917.55it/s]
82%|████████▏ | 16386/20000 [00:17<00:03, 918.46it/s]
82%|████████▏ | 16478/20000 [00:18<00:03, 917.59it/s]
83%|████████▎ | 16570/20000 [00:18<00:03, 917.05it/s]
83%|████████▎ | 16662/20000 [00:18<00:03, 916.92it/s]
84%|████████▍ | 16754/20000 [00:18<00:03, 916.19it/s]
84%|████████▍ | 16846/20000 [00:18<00:03, 915.72it/s]
85%|████████▍ | 16938/20000 [00:18<00:03, 915.94it/s]
85%|████████▌ | 17030/20000 [00:18<00:03, 916.37it/s]
86%|████████▌ | 17123/20000 [00:18<00:03, 917.60it/s]
86%|████████▌ | 17216/20000 [00:18<00:03, 919.00it/s]
87%|████████▋ | 17308/20000 [00:18<00:02, 918.36it/s]
87%|████████▋ | 17400/20000 [00:19<00:02, 916.90it/s]
87%|████████▋ | 17493/20000 [00:19<00:02, 918.85it/s]
88%|████████▊ | 17585/20000 [00:19<00:02, 915.16it/s]
88%|████████▊ | 17677/20000 [00:19<00:02, 913.78it/s]
89%|████████▉ | 17769/20000 [00:19<00:02, 911.82it/s]
89%|████████▉ | 17861/20000 [00:19<00:02, 912.69it/s]
90%|████████▉ | 17954/20000 [00:19<00:02, 914.92it/s]
90%|█████████ | 18046/20000 [00:19<00:02, 915.91it/s]
91%|█████████ | 18138/20000 [00:19<00:02, 916.24it/s]
91%|█████████ | 18230/20000 [00:19<00:01, 914.08it/s]
92%|█████████▏| 18322/20000 [00:20<00:01, 914.42it/s]
92%|█████████▏| 18414/20000 [00:20<00:01, 915.67it/s]
93%|█████████▎| 18506/20000 [00:20<00:01, 912.95it/s]
93%|█████████▎| 18598/20000 [00:20<00:01, 912.86it/s]
93%|█████████▎| 18690/20000 [00:20<00:01, 912.41it/s]
94%|█████████▍| 18782/20000 [00:20<00:01, 914.46it/s]
94%|█████████▍| 18874/20000 [00:20<00:01, 908.77it/s]
95%|█████████▍| 18966/20000 [00:20<00:01, 911.74it/s]
95%|█████████▌| 19058/20000 [00:20<00:01, 911.26it/s]
96%|█████████▌| 19150/20000 [00:20<00:00, 907.51it/s]
96%|█████████▌| 19241/20000 [00:21<00:00, 905.61it/s]
97%|█████████▋| 19332/20000 [00:21<00:00, 903.12it/s]
97%|█████████▋| 19423/20000 [00:21<00:00, 896.40it/s]
98%|█████████▊| 19514/20000 [00:21<00:00, 899.39it/s]
98%|█████████▊| 19604/20000 [00:21<00:00, 897.53it/s]
98%|█████████▊| 19696/20000 [00:21<00:00, 903.69it/s]
99%|█████████▉| 19788/20000 [00:21<00:00, 906.77it/s]
99%|█████████▉| 19880/20000 [00:21<00:00, 909.18it/s]
100%|█████████▉| 19972/20000 [00:21<00:00, 911.65it/s]
100%|██████████| 20000/20000 [00:21<00:00, 912.58it/s]
sampler = inv_result_fixed_d_sampler.sampler
az_idata = az.from_emcee(sampler, var_names=labels)
az_idata.get("posterior")
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=ref_good_model, label_model="reference good model", color_model="red",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from reference good model", color_d_pred="red", axes=axes)
# plot the model and d_pred for inverted model, and d_obs
plot_model_and_data(model=inv_result_sw_field.model,
label_model="inverted model from field data", color_model="green",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from inverted model", color_d_pred="green", axes=axes)
# plot randomly selected samples and data predictions from samples
flat_samples = sampler.get_chain(discard=1000, thin=300, flat=True)
rand_indices = np.random.randint(len(flat_samples), size=100)
for idx in rand_indices:
sample = flat_samples[idx]
label_model = "sample models" if idx == 0 else None
label_d_pred = "d_pred from samples" if idx == 0 else None
plot_model_and_data(model=sample, label_model=label_model, color_model="gray",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred=label_d_pred, color_d_pred="gray", axes=axes, light_thin=True)
# plot d_obs
plot_data(field_d_obs, field_d_periods, ax=axes[1], scatter=True, color="orange", s=8, label="d_obs")
axes[0].set_ylim(100, 0)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.4))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd25fb0f790>
More steps
Similar to our earlier fixed-dimensional sampling run on the synthetic data, we are not sampling enough due to time limit.
On a seperate experiment, we ran 200_000 steps and produced the following samples plot.
Trans-dimensional sampling#
def forward_interp_for_bayesbay(state):
vs = state["voronoi"]["vs"]
voronoi_sites = state["voronoi"]["discretization"]
depths = (voronoi_sites[:-1] + voronoi_sites[1:]) / 2
thicknesses = depths - np.insert(depths[:-1], 0, 0)
model = form_layercake_model(thicknesses, vs)
return forward_sw_interp(model, field_d_periods)
targets = [bayesbay.Target("rayleigh", field_d_obs, covariance_mat_inv=1/noise_level**2)]
fwd_funcs = [forward_interp_for_bayesbay]
my_log_likelihood = bayesbay.LogLikelihood(targets, fwd_funcs)
param_vs = bayesbay.prior.UniformPrior(
name="vs",
vmin=[2.7, 3.2, 3.75],
vmax=[4, 4.75, 5],
position=[0, 40, 80],
perturb_std=0.15
)
def param_vs_initialize(param, positions):
vmin, vmax = param.get_vmin_vmax(positions)
sorted_vals = np.sort(np.random.uniform(vmin, vmax, positions.size))
for i in range (len(sorted_vals)):
val = sorted_vals[i]
vmin_i = vmin if np.isscalar(vmin) else vmin[i]
vmax_i = vmax if np.isscalar(vmax) else vmax[i]
if val < vmin_i or val > vmax_i:
if val > vmax_i: sorted_vals[i] = vmax_i
if val < vmin_i: sorted_vals[i] = vmin_i
return sorted_vals
param_vs.set_custom_initialize(param_vs_initialize)
parameterization = bayesbay.parameterization.Parameterization(
bayesbay.discretization.Voronoi1D(
name="voronoi",
vmin=0,
vmax=150,
perturb_std=10,
n_dimensions=None,
n_dimensions_min=4,
n_dimensions_max=20,
parameters=[param_vs],
)
)
my_perturbation_funcs = parameterization.perturbation_functions
n_chains=12
walkers_start = []
for i in range(n_chains):
walkers_start.append(parameterization.initialize())
Define ``InversionOptions``
inv_options_field_trans_d_sampling = cofi.InversionOptions()
inv_options_field_trans_d_sampling.set_tool("bayesbay")
inv_options_field_trans_d_sampling.set_params(
walkers_starting_states=walkers_start,
perturbation_funcs=my_perturbation_funcs,
log_like_ratio_func=my_log_likelihood,
n_chains=n_chains,
n_iterations=3_000,
burnin_iterations=1_000,
verbose=False,
save_every=200,
)
Define ``Inversion`` and run
inversion_field_trans_d_sampler = cofi.Inversion(sw_field_problem,
inv_options_field_trans_d_sampling)
inv_result_field_trans_d_sampler = inversion_field_trans_d_sampler.run()
# plot the model and d_pred for starting model
axes = plot_model_and_data(model=init_model, label_model="starting model", color_model="black",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from starting model", color_d_pred="black")
# plot the model and d_pred for true model
plot_model_and_data(model=ref_good_model, label_model="reference good model", color_model="red",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from reference good model", color_d_pred="red", axes=axes)
# plot the model and d_pred for inverted model, and d_obs
plot_model_and_data(model=inv_result_sw_field.model,
label_model="inverted model from field data", color_model="green",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred="d_pred from inverted model", color_d_pred="green", axes=axes)
# plot randomly selected samples and data predictions from samples
flat_samples = sampler.get_chain(discard=1000, thin=300, flat=True)
rand_indices = np.random.randint(len(flat_samples), size=100)
for i, sample in enumerate(samples):
label_model = "sample models" if i == 0 else None
label_d_pred = "d_pred from samples" if i == 0 else None
plot_model_and_data(model=sample, label_model=label_model, color_model="gray",
forward_func=forward_sw_interp, periods=field_d_periods_logspace,
label_d_pred=label_d_pred, color_d_pred="gray", axes=axes, light_thin=True)
# plot d_obs
plot_data(field_d_obs, field_d_periods, ax=axes[1], scatter=True, color="orange", s=8, label="d_obs")
axes[0].set_ylim(100, 0)
axes[0].legend(loc="lower center", bbox_to_anchor=(0.5, -0.4))
axes[1].legend(loc="lower center", bbox_to_anchor=(0.5, -0.46));
<matplotlib.legend.Legend object at 0x7fd0a8f0b850>
Watermark#
watermark_list = ["cofi", "numpy", "matplotlib", "scipy", "emcee", "bayesbay"]
for pkg in watermark_list:
pkg_var = __import__(pkg)
print(pkg, getattr(pkg_var, "__version__"))
cofi 0.2.8
numpy 1.26.4
matplotlib 3.8.3
scipy 1.12.0
emcee 3.1.5
bayesbay 0.3.0
sphinx_gallery_thumbnail_number = -1
Total running time of the script: (3 minutes 13.920 seconds)