Surface wave and receiver function - joint inversion (synthetic data)#

Open In Colab

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 extend the example where CoFI has been used for the inversion of Rayleigh wave phase velocities for a 1D layered earth to a joint inversion where we also account for receiver functions.

Learning outcomes

  • A demonstration of CoFI’s ability to switch between parameter estimation and ensemble methods.

  • An application of CoFI for a joint inversion, here of Rayleigh wave pahse velocity and receiver function data, to a synthetic dataset

Utilities preparation#

In this example, we look at a joint inversion problem of surface wave and receiver function.

We use pysurf96 for computing the forward step of surface wave, and use pyhk for receiver function calculations.

# -------------------------------------------------------- #
#                                                          #
#     Uncomment below to set up environment on "colab"     #
#                                                          #
# -------------------------------------------------------- #

# !pip install -U cofi
# !pip install 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
# If this notebook is run locally pysurf96 needs to be installed separately by uncommenting the following line,
# that is by removing the # and the white space between it and the exclammation mark.
# !pip install -U cofi git+https://github.com/inlab-geo/pysurf96.git@ctypes
import glob
import numpy as np
import scipy
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

import pysurf96
import bayesbay
import cofi
import pyhk
np.seterr(all="ignore");
{'divide': 'ignore', 'over': 'ignore', 'under': 'ignore', 'invalid': 'ignore'}

Model vector

# display theory on the 1D model parameterisation
from IPython.display import display, Markdown

with open("../../theory/misc_1d_model_parameterisation.md", "r") as f:
    content = f.read()

display(Markdown(content))
<IPython.core.display.Markdown object>
# layercake model utilities
def form_layercake_model(thicknesses, vs):
    model = np.zeros((len(vs)*2-1,))
    model[1::2] = thicknesses
    model[::2] = vs
    return model

def split_layercake_model(model):
    thicknesses = model[1::2]
    vs = model[::2]
    return thicknesses, vs
# voronoi model utilities
def form_voronoi_model(voronoi_sites, vs):
    return np.hstack((vs, voronoi_sites))

def split_voronoi_model(model):
    voronoi_sites = model[len(model)//2:]
    vs = model[:len(model)//2]
    return voronoi_sites, vs
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

Interfacing to pysurf96

# 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>
VP_VS = 1.77
RHO_VP_K = 0.32
RHO_VP_B = 0.77
periods = np.geomspace(3, 80, 20)
# 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 pysurf96.surf96(
        thicknesses,
        vp,
        vs,
        rho,
        periods,
        wave="rayleigh",
        mode=1,
        velocity="phase",
        flat_earth=False,
    )
t_shift = 5
t_duration = 25
t_sampling_interval = 0.1
gauss = 1
ray_param_s_km = 0.07
# forward through rf in pyhk
def forward_rf(
    model,
    t_shift=t_shift,
    t_duration=t_duration,
    t_sampling_interval=t_sampling_interval,
    gauss=gauss,
    ray_param_s_km=ray_param_s_km,
    return_times=False
):
    h, vs = split_layercake_model(model)
    data = pyhk.rfcalc(ps=0, thik=h, beta=vs, kapa=np.ones((len(vs),))*VP_VS, p=ray_param_s_km,
                      duration=t_duration, dt=t_sampling_interval, shft=t_shift, gauss=gauss)
    if return_times:
        times = np.arange(len(data)) * t_sampling_interval - t_shift
        return data, times
    else:
        return data

Numerical Jacobian

def jacobian(model, data_length, fwd, fwd_kwargs, relative_step=0.01):
    jac = np.zeros((data_length, len(model)))
    original_dpred = fwd(model, **fwd_kwargs)
    for i in range(len(model)):
        perturbed_model = model.copy()
        step = relative_step * model[i]
        perturbed_model[i] += step
        perturbed_dpred = fwd(perturbed_model, **fwd_kwargs)
        derivative = (perturbed_dpred - original_dpred) / step
        jac[:, i] = derivative
    return jac

Plotting

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(x, y, ax=None, scatter=False, xlabel=None, ylabel=None,
              title="surface wave 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(x, y, **plotting_style)
    else:
        ax.plot(x, y, **plotting_style)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.set_title(title)
    return ax
def plot_sw_data(rayleigh_phase_velocities, periods, ax=None, scatter=False,
                 title="surface wave data", **kwargs):
    return plot_data(x=periods,
                     y=rayleigh_phase_velocities,
                     ax=ax,
                     scatter=scatter,
                     title=title,
                     xlabel="Periods (s)",
                     ylabel="Rayleigh phase velocities (km/s)",
                     **kwargs)

def plot_rf_data(rf_data, rf_times, ax=None, scatter=False,
                 title="receiver function data", **kwargs):
    return plot_data(x=rf_times,
                     y=rf_data,
                     ax=ax,
                     scatter=scatter,
                     title=title,
                     xlabel="Times (s)",
                     ylabel="Receiver function amplitudes",
                     **kwargs)

Generate synthetic data#

true_thickness = np.array([10, 10, 15, 20, 20, 20, 20, 20])
true_voronoi_positions = np.array([5, 15, 25, 45, 65, 85, 105, 125, 145])
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_thickness, true_vs)
RAYLEIGH_STD = 0.02
RF_STD = 0.015
rayleigh = forward_sw(true_model, periods)
rayleigh_dobs = rayleigh + np.random.normal(0, RAYLEIGH_STD, rayleigh.size)

rf, rf_times = forward_rf(true_model, return_times=True)
rf_dobs = rf + np.random.normal(0, RF_STD, rf.size)
_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 2.5, 2.5]})

# plot true model
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
ax1.grid()

# plot surface wave data
plot_sw_data(rayleigh, periods, ax=ax2, color="orange", label="true rayleigh data (noiseless)")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="brown", s=4,
          label="observed rayleigh data (noisy)")
ax2.grid()

# plot receiver function data
plot_rf_data(rf, rf_times, ax=ax3, color="lightblue", label="true receiver function data (noiseless)")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="darkblue", s=2,
          label="observed receiver function data (noisy)")
ax3.grid()

ax1.legend(loc="lower center", bbox_to_anchor=(0.5, -0.4))
ax2.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax3.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))

plt.tight_layout()

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)
_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 2.5, 2.5]})

# plot true model
plot_model(init_model, ax=ax1, alpha=1, color="purple", label="starting model")
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
ax1.grid()

# plot surface wave data
plot_sw_data(forward_sw(init_model, periods), periods, ax=ax2, color="purple",
             label="predicted rayleigh data from starting model")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="orange", s=4,
          label="observed rayleigh data (noisy)")
ax2.grid()

# plot receiver function data
plot_rf_data(forward_rf(init_model), rf_times, ax=ax3, color="purple",
             label="predicted receiver function data from starting model")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="darkblue", s=2,
          label="observed receiver function data (noisy)")
ax3.grid()

ax1.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax2.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax3.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))

plt.tight_layout()
my_reg = cofi.utils.QuadraticReg(
    weighting_matrix="damping",
    model_shape=(n_dims,),
    reference_model=init_model
)
def my_objective(model, fwd_funcs, d_obs_list, lamda=1.0):
    data_misfit = 0
    for (fwd, fwd_kwargs), d_obs in zip(fwd_funcs, d_obs_list):
        d_pred = fwd(model, **fwd_kwargs)
        data_misfit += np.sum((d_obs - d_pred) ** 2)
    reg = my_reg(model)
    return data_misfit + lamda * reg

def my_objective_gradient(model, fwd_funcs, d_obs_list, lamda=1.0):
    data_misfit_grad = 0
    for (fwd, fwd_kwargs), d_obs in zip(fwd_funcs, d_obs_list):
        d_pred = fwd(model, **fwd_kwargs)
        jac = jacobian(model, len(d_obs), fwd, fwd_kwargs)
        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_funcs, d_obs_list, lamda=1.0):
    data_misfit_hess = 0
    for (fwd, fwd_kwargs), d_obs in zip(fwd_funcs, d_obs_list):
        jac = jacobian(model, len(d_obs), fwd, fwd_kwargs)
        data_misfit_hess += 2 * jac.T @ jac
    reg_hess = my_reg.hessian(model)
    return data_misfit_hess + lamda * reg_hess
fwd_funcs = [
    (forward_sw, {"periods": periods}),
    (forward_rf, {
        "t_shift": t_shift,
        "t_duration": t_duration,
        "t_sampling_interval": t_sampling_interval,
        "gauss": gauss,
        "ray_param_s_km": ray_param_s_km
    })
]

d_obs_list = [rayleigh_dobs, rf_dobs]

Optimisation with no damping#

lamda = 0

kwargs = {
    "fwd_funcs": fwd_funcs,
    "d_obs_list": d_obs_list,
    "lamda": lamda
}
joint_problem_no_reg = cofi.BaseProblem()
joint_problem_no_reg.set_objective(my_objective, kwargs=kwargs)
joint_problem_no_reg.set_gradient(my_objective_gradient, kwargs=kwargs)
joint_problem_no_reg.set_hessian(my_objective_hessian, kwargs=kwargs)
joint_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(joint_problem_no_reg, inv_options_optimiser)
inv_res_optimiser_no_reg = inv_optimiser_no_reg.run()
/home/kitc/actions-runner/_work/cofi/cofi/src/cofi/tools/_scipy_opt_min.py:120: RuntimeWarning: Method trust-exact does not use Hessian-vector product information (hessp).
  return minimize(

Plot results

_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 2.5, 2.5]})

# plot true model
plot_model(inv_res_optimiser_no_reg.model, ax=ax1, alpha=1, color="purple",
           label="inverted model")
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
ax1.grid()

# plot surface wave data
plot_sw_data(forward_sw(inv_res_optimiser_no_reg.model, periods),
             periods, ax=ax2, color="purple",
             label="predicted rayleigh data from inverted model")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="orange", s=4,
          label="observed rayleigh data (noisy)")
ax2.grid()

# plot receiver function data
plot_rf_data(forward_rf(inv_res_optimiser_no_reg.model), rf_times,
             ax=ax3, color="purple",
             label="predicted receiver function data from inverted model")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="darkblue", s=2,
          label="observed receiver function data (noisy)")
ax3.grid()

ax1.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax2.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax3.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))

plt.tight_layout()

Optimal damping#

Oh no! The inverted model doesn’t look good, and it even has negative thicknesses.

Maybe adding a damping term to our objective function would help… but how can we determine a good damping factor?

The InversionPool in CoFI can help you answer it.

lambdas = np.logspace(-6, 6, 15)

my_lcurve_problems = []
for lamb in lambdas:
    my_problem = cofi.BaseProblem()
    kwargs = {
        "fwd_funcs": fwd_funcs,
        "d_obs_list": d_obs_list,
        "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 = 0
    for (fwd, fwd_kwargs), d_obs in zip(fwd_funcs, d_obs_list):
        d_pred = fwd(m, **fwd_kwargs)
        res_norm += np.sum((d_obs - d_pred) ** 2)
    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.05237651870817549, 15.546110466623707
Finished inversion with lambda=7.196856730011514e-06: 0.05262528266554743, 9.323561550075398
Finished inversion with lambda=5.1794746792312125e-05: 0.053476267842756095, 5.957471484627645
Finished inversion with lambda=0.0003727593720314938: 0.05594853540572327, 4.325082609636359
Finished inversion with lambda=0.0026826957952797246: 0.06486338839997631, 3.4002331042717904
Finished inversion with lambda=0.019306977288832496: 0.1459704713722506, 1.584105320807178
Finished inversion with lambda=0.1389495494373136: 0.1990707095534692, 1.0133321039950136
Finished inversion with lambda=1.0: 0.45318236855978455, 0.6603421824042947
Finished inversion with lambda=7.196856730011514: 1.4062814854475048, 0.3126534069078207
Finished inversion with lambda=51.79474679231202: 2.838901390315139, 0.0690310884927589
Finished inversion with lambda=372.7593720314938: 3.278249150812174, 0.010384097649886072
Finished inversion with lambda=2682.6957952797275: 3.3481516748245808, 0.001458934986341425
Finished inversion with lambda=19306.977288832455: 3.3580553037015863, 0.00020305801442491956
Finished inversion with lambda=138949.5494373136: 3.3594547056318564, 2.8221956325204102e-05
Finished inversion with lambda=1000000.0: 3.3596434920653397, 3.9215659446745076e-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.14 would be good.

lamda = 0.14

kwargs = {
    "fwd_funcs": fwd_funcs,
    "d_obs_list": d_obs_list,
    "lamda": lamda
}
joint_problem = cofi.BaseProblem()
joint_problem.set_objective(my_objective, kwargs=kwargs)
joint_problem.set_gradient(my_objective_gradient, kwargs=kwargs)
joint_problem.set_hessian(my_objective_hessian, kwargs=kwargs)
joint_problem.set_initial_model(init_model)

Define ``Inversion`` and run

inv_optimiser = cofi.Inversion(joint_problem, inv_options_optimiser)
inv_res_optimiser = inv_optimiser.run()

Plot results

_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 2.5, 2.5]})

# plot true model
plot_model(inv_res_optimiser.model, ax=ax1, alpha=1, color="purple",
           label="inverted model")
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
ax1.grid()

# plot surface wave data
plot_sw_data(forward_sw(inv_res_optimiser_no_reg.model, periods),
             periods, ax=ax2, color="purple",
             label="predicted rayleigh data from inverted model")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="orange", s=4,
          label="observed rayleigh data (noisy)")
ax2.grid()

# plot receiver function data
plot_rf_data(forward_rf(inv_res_optimiser.model), rf_times,
             ax=ax3, color="purple",
             label="predicted receiver function data from inverted model")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="darkblue", s=2,
          label="observed receiver function data (noisy)")
ax3.grid()

ax1.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax2.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))
ax3.legend(loc="lower center", bbox_to_anchor=(0.5, -0.5))

plt.tight_layout()

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
# inverse data covariance matrix
Cdinv_rayleigh = np.eye(len(rayleigh_dobs)) / (RAYLEIGH_STD**2)
Cdinv_rf = np.eye(len(rf_dobs)) / (RF_STD**2)
Cdinv_list = [Cdinv_rayleigh, Cdinv_rf]

def my_log_likelihood(
    model,
    fwd_funcs=fwd_funcs,
    d_obs_list=d_obs_list,
    Cdinv_list=Cdinv_list
):
    log_like_sum = 0
    for (fwd, fwd_kwargs), d_obs, Cdinv in zip(fwd_funcs, d_obs_list, Cdinv_list):
        try:
            d_pred = fwd(model, **fwd_kwargs)
        except:
            return float("-inf")
        residual = d_obs - d_pred
        log_like_sum += -0.5 * residual @ (Cdinv @ residual).T
    return log_like_sum
n_walkers = 40

my_walkers_start = np.ones((n_walkers, n_dims)) * inv_res_optimiser.model
for i in range(n_walkers):
    my_walkers_start[i,:] += np.random.normal(0, 0.5, n_dims)
joint_problem.set_log_prior(my_log_prior)
joint_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

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%|▌         | 114/2000 [00:00<00:01, 1136.78it/s]
 11%|█▏        | 228/2000 [00:00<00:01, 1136.09it/s]
 17%|█▋        | 343/2000 [00:00<00:01, 1141.47it/s]
 23%|██▎       | 459/2000 [00:00<00:01, 1147.25it/s]
 29%|██▉       | 575/2000 [00:00<00:01, 1150.94it/s]
 35%|███▍      | 691/2000 [00:00<00:01, 1152.96it/s]
 40%|████      | 807/2000 [00:00<00:01, 1155.10it/s]
 46%|████▌     | 924/2000 [00:00<00:00, 1159.35it/s]
 52%|█████▏    | 1040/2000 [00:00<00:00, 1155.68it/s]
 58%|█████▊    | 1158/2000 [00:01<00:00, 1163.03it/s]
 64%|██████▍   | 1275/2000 [00:01<00:00, 1163.86it/s]
 70%|██████▉   | 1395/2000 [00:01<00:00, 1171.83it/s]
 76%|███████▌  | 1513/2000 [00:01<00:00, 1172.52it/s]
 82%|████████▏ | 1632/2000 [00:01<00:00, 1177.45it/s]
 88%|████████▊ | 1752/2000 [00:01<00:00, 1183.11it/s]
 94%|█████████▎| 1873/2000 [00:01<00:00, 1190.21it/s]
100%|█████████▉| 1993/2000 [00:01<00:00, 1190.76it/s]
100%|██████████| 2000/2000 [00:01<00:00, 1168.18it/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)

pc = az.plot_trace_dist(
    az_idata_prior,
    visuals={"xlabel_trace": False, "trace": {"color": "C0", "lw": 0.5}, "dist": {"color": "C0", "lw": 0.5}},
    figure_kwargs={"figsize": (12, 40), "constrained_layout": True},
)

n_vars = len(az_idata_prior.posterior.data_vars)
var_names = list(az_idata_prior.posterior.data_vars)
for i in range(n_vars):
    ax1 = pc.iget_target(i, 0)
    ax2 = pc.iget_target(i, 1)
    ax1.set_title(var_names[i])
    ax1.set_xlabel("parameter value")
    ax1.set_ylabel("density value")
    ax2.set_title(var_names[i])
    ax2.set_xlabel("number of iterations")
    ax2.set_ylabel("parameter value")
    ax2.margins(x=0)

Sample the posterior#

inversion_fixed_d_sampler = cofi.Inversion(joint_problem, inv_options_fixed_d_sampling)
inv_result_fixed_d_sampler = inversion_fixed_d_sampler.run()
  0%|          | 0/2000 [00:00<?, ?it/s]
  0%|          | 5/2000 [00:00<00:43, 45.46it/s]
  0%|          | 10/2000 [00:00<00:53, 37.18it/s]
  1%|          | 14/2000 [00:00<00:58, 33.90it/s]
  1%|          | 18/2000 [00:00<01:02, 31.80it/s]
  1%|          | 22/2000 [00:00<01:06, 29.93it/s]
  1%|▏         | 26/2000 [00:00<01:07, 29.09it/s]
  1%|▏         | 29/2000 [00:00<01:09, 28.46it/s]
  2%|▏         | 32/2000 [00:01<01:09, 28.16it/s]
  2%|▏         | 35/2000 [00:01<01:10, 27.99it/s]
  2%|▏         | 38/2000 [00:01<01:10, 27.89it/s]
  2%|▏         | 41/2000 [00:01<01:10, 27.71it/s]
  2%|▏         | 44/2000 [00:01<01:10, 27.62it/s]
  2%|▏         | 47/2000 [00:01<01:10, 27.57it/s]
  2%|▎         | 50/2000 [00:01<01:10, 27.58it/s]
  3%|▎         | 53/2000 [00:01<01:10, 27.56it/s]
  3%|▎         | 56/2000 [00:01<01:10, 27.44it/s]
  3%|▎         | 59/2000 [00:02<01:10, 27.41it/s]
  3%|▎         | 62/2000 [00:02<01:10, 27.40it/s]
  3%|▎         | 65/2000 [00:02<01:10, 27.42it/s]
  3%|▎         | 68/2000 [00:02<01:10, 27.45it/s]
  4%|▎         | 71/2000 [00:02<01:10, 27.28it/s]
  4%|▎         | 74/2000 [00:02<01:11, 27.09it/s]
  4%|▍         | 77/2000 [00:02<01:11, 27.05it/s]
  4%|▍         | 80/2000 [00:02<01:10, 27.13it/s]
  4%|▍         | 83/2000 [00:02<01:10, 27.16it/s]
  4%|▍         | 86/2000 [00:03<01:10, 27.20it/s]
  4%|▍         | 89/2000 [00:03<01:10, 27.16it/s]
  5%|▍         | 92/2000 [00:03<01:10, 27.14it/s]
  5%|▍         | 95/2000 [00:03<01:10, 27.17it/s]
  5%|▍         | 98/2000 [00:03<01:10, 27.14it/s]
  5%|▌         | 101/2000 [00:03<01:10, 26.94it/s]
  5%|▌         | 104/2000 [00:03<01:10, 26.93it/s]
  5%|▌         | 107/2000 [00:03<01:10, 26.99it/s]
  6%|▌         | 110/2000 [00:03<01:09, 27.07it/s]
  6%|▌         | 113/2000 [00:04<01:09, 27.02it/s]
  6%|▌         | 116/2000 [00:04<01:09, 27.09it/s]
  6%|▌         | 119/2000 [00:04<01:09, 27.12it/s]
  6%|▌         | 122/2000 [00:04<01:08, 27.23it/s]
  6%|▋         | 125/2000 [00:04<01:08, 27.25it/s]
  6%|▋         | 128/2000 [00:04<01:08, 27.27it/s]
  7%|▋         | 131/2000 [00:04<01:08, 27.26it/s]
  7%|▋         | 134/2000 [00:04<01:08, 27.14it/s]
  7%|▋         | 137/2000 [00:04<01:08, 27.33it/s]
  7%|▋         | 140/2000 [00:05<01:08, 27.32it/s]
  7%|▋         | 143/2000 [00:05<01:08, 27.24it/s]
  7%|▋         | 146/2000 [00:05<01:08, 27.24it/s]
  7%|▋         | 149/2000 [00:05<01:07, 27.33it/s]
  8%|▊         | 152/2000 [00:05<01:07, 27.42it/s]
  8%|▊         | 155/2000 [00:05<01:07, 27.30it/s]
  8%|▊         | 158/2000 [00:05<01:07, 27.36it/s]
  8%|▊         | 161/2000 [00:05<01:06, 27.49it/s]
  8%|▊         | 164/2000 [00:05<01:07, 27.38it/s]
  8%|▊         | 167/2000 [00:06<01:06, 27.37it/s]
  8%|▊         | 170/2000 [00:06<01:06, 27.33it/s]
  9%|▊         | 173/2000 [00:06<01:06, 27.33it/s]
  9%|▉         | 176/2000 [00:06<01:06, 27.41it/s]
  9%|▉         | 179/2000 [00:06<01:06, 27.44it/s]
  9%|▉         | 182/2000 [00:06<01:05, 27.57it/s]
  9%|▉         | 185/2000 [00:06<01:06, 27.38it/s]
  9%|▉         | 188/2000 [00:06<01:06, 27.39it/s]
 10%|▉         | 191/2000 [00:06<01:05, 27.52it/s]
 10%|▉         | 194/2000 [00:06<01:05, 27.41it/s]
 10%|▉         | 197/2000 [00:07<01:07, 26.87it/s]
 10%|█         | 200/2000 [00:07<01:06, 27.00it/s]
 10%|█         | 203/2000 [00:07<01:06, 26.83it/s]
 10%|█         | 206/2000 [00:07<01:06, 26.83it/s]
 10%|█         | 209/2000 [00:07<01:07, 26.64it/s]
 11%|█         | 212/2000 [00:07<01:06, 26.78it/s]
 11%|█         | 215/2000 [00:07<01:06, 27.01it/s]
 11%|█         | 218/2000 [00:07<01:05, 27.12it/s]
 11%|█         | 221/2000 [00:07<01:05, 27.15it/s]
 11%|█         | 224/2000 [00:08<01:05, 27.28it/s]
 11%|█▏        | 227/2000 [00:08<01:04, 27.47it/s]
 12%|█▏        | 230/2000 [00:08<01:04, 27.32it/s]
 12%|█▏        | 233/2000 [00:08<01:04, 27.40it/s]
 12%|█▏        | 236/2000 [00:08<01:04, 27.48it/s]
 12%|█▏        | 239/2000 [00:08<01:04, 27.35it/s]
 12%|█▏        | 242/2000 [00:08<01:04, 27.41it/s]
 12%|█▏        | 245/2000 [00:08<01:04, 27.40it/s]
 12%|█▏        | 248/2000 [00:08<01:03, 27.46it/s]
 13%|█▎        | 251/2000 [00:09<01:03, 27.41it/s]
 13%|█▎        | 254/2000 [00:09<01:03, 27.33it/s]
 13%|█▎        | 257/2000 [00:09<01:03, 27.32it/s]
 13%|█▎        | 260/2000 [00:09<01:03, 27.29it/s]
 13%|█▎        | 263/2000 [00:09<01:03, 27.29it/s]
 13%|█▎        | 266/2000 [00:09<01:03, 27.33it/s]
 13%|█▎        | 269/2000 [00:09<01:03, 27.34it/s]
 14%|█▎        | 272/2000 [00:09<01:02, 27.52it/s]
 14%|█▍        | 275/2000 [00:09<01:02, 27.49it/s]
 14%|█▍        | 278/2000 [00:10<01:03, 27.33it/s]
 14%|█▍        | 281/2000 [00:10<01:02, 27.36it/s]
 14%|█▍        | 284/2000 [00:10<01:02, 27.33it/s]
 14%|█▍        | 287/2000 [00:10<01:02, 27.40it/s]
 14%|█▍        | 290/2000 [00:10<01:02, 27.44it/s]
 15%|█▍        | 293/2000 [00:10<01:02, 27.49it/s]
 15%|█▍        | 296/2000 [00:10<01:01, 27.68it/s]
 15%|█▍        | 299/2000 [00:10<01:01, 27.78it/s]
 15%|█▌        | 302/2000 [00:10<01:01, 27.65it/s]
 15%|█▌        | 305/2000 [00:11<01:01, 27.46it/s]
 15%|█▌        | 308/2000 [00:11<01:01, 27.46it/s]
 16%|█▌        | 311/2000 [00:11<01:01, 27.40it/s]
 16%|█▌        | 314/2000 [00:11<01:01, 27.44it/s]
 16%|█▌        | 317/2000 [00:11<01:01, 27.52it/s]
 16%|█▌        | 320/2000 [00:11<01:00, 27.58it/s]
 16%|█▌        | 323/2000 [00:11<01:00, 27.53it/s]
 16%|█▋        | 326/2000 [00:11<01:00, 27.60it/s]
 16%|█▋        | 329/2000 [00:11<01:00, 27.56it/s]
 17%|█▋        | 332/2000 [00:12<01:00, 27.51it/s]
 17%|█▋        | 335/2000 [00:12<01:01, 27.24it/s]
 17%|█▋        | 338/2000 [00:12<01:01, 27.12it/s]
 17%|█▋        | 341/2000 [00:12<01:00, 27.40it/s]
 17%|█▋        | 344/2000 [00:12<01:00, 27.55it/s]
 17%|█▋        | 347/2000 [00:12<01:00, 27.52it/s]
 18%|█▊        | 350/2000 [00:12<00:59, 27.56it/s]
 18%|█▊        | 353/2000 [00:12<00:59, 27.56it/s]
 18%|█▊        | 356/2000 [00:12<00:59, 27.63it/s]
 18%|█▊        | 359/2000 [00:13<00:59, 27.60it/s]
 18%|█▊        | 362/2000 [00:13<00:59, 27.58it/s]
 18%|█▊        | 365/2000 [00:13<00:58, 27.80it/s]
 18%|█▊        | 368/2000 [00:13<00:59, 27.65it/s]
 19%|█▊        | 371/2000 [00:13<00:58, 27.76it/s]
 19%|█▊        | 374/2000 [00:13<00:58, 27.70it/s]
 19%|█▉        | 377/2000 [00:13<00:58, 27.89it/s]
 19%|█▉        | 380/2000 [00:13<00:58, 27.72it/s]
 19%|█▉        | 383/2000 [00:13<00:58, 27.75it/s]
 19%|█▉        | 386/2000 [00:13<00:58, 27.63it/s]
 19%|█▉        | 389/2000 [00:14<00:58, 27.45it/s]
 20%|█▉        | 392/2000 [00:14<00:58, 27.43it/s]
 20%|█▉        | 395/2000 [00:14<00:58, 27.62it/s]
 20%|█▉        | 398/2000 [00:14<00:58, 27.56it/s]
 20%|██        | 401/2000 [00:14<00:58, 27.46it/s]
 20%|██        | 404/2000 [00:14<00:57, 27.72it/s]
 20%|██        | 407/2000 [00:14<00:57, 27.82it/s]
 20%|██        | 410/2000 [00:14<00:56, 28.00it/s]
 21%|██        | 413/2000 [00:14<00:56, 28.06it/s]
 21%|██        | 416/2000 [00:15<00:56, 28.07it/s]
 21%|██        | 419/2000 [00:15<00:56, 28.01it/s]
 21%|██        | 422/2000 [00:15<00:55, 28.19it/s]
 21%|██▏       | 425/2000 [00:15<00:55, 28.14it/s]
 21%|██▏       | 428/2000 [00:15<00:55, 28.40it/s]
 22%|██▏       | 431/2000 [00:15<00:55, 28.34it/s]
 22%|██▏       | 434/2000 [00:15<00:55, 28.10it/s]
 22%|██▏       | 437/2000 [00:15<00:55, 28.27it/s]
 22%|██▏       | 440/2000 [00:15<00:55, 28.33it/s]
 22%|██▏       | 443/2000 [00:16<00:55, 28.02it/s]
 22%|██▏       | 446/2000 [00:16<00:55, 28.09it/s]
 22%|██▏       | 449/2000 [00:16<00:55, 27.97it/s]
 23%|██▎       | 452/2000 [00:16<00:55, 28.05it/s]
 23%|██▎       | 455/2000 [00:16<00:54, 28.13it/s]
 23%|██▎       | 458/2000 [00:16<00:54, 28.46it/s]
 23%|██▎       | 461/2000 [00:16<00:54, 28.29it/s]
 23%|██▎       | 464/2000 [00:16<00:54, 28.39it/s]
 23%|██▎       | 467/2000 [00:16<00:54, 28.26it/s]
 24%|██▎       | 470/2000 [00:16<00:54, 28.29it/s]
 24%|██▎       | 473/2000 [00:17<00:53, 28.32it/s]
 24%|██▍       | 476/2000 [00:17<00:53, 28.32it/s]
 24%|██▍       | 479/2000 [00:17<00:54, 27.96it/s]
 24%|██▍       | 482/2000 [00:17<00:54, 27.74it/s]
 24%|██▍       | 485/2000 [00:17<00:54, 27.56it/s]
 24%|██▍       | 488/2000 [00:17<00:54, 27.69it/s]
 25%|██▍       | 491/2000 [00:17<00:53, 28.00it/s]
 25%|██▍       | 494/2000 [00:17<00:53, 27.91it/s]
 25%|██▍       | 497/2000 [00:17<00:53, 28.00it/s]
 25%|██▌       | 500/2000 [00:18<00:53, 28.05it/s]
 25%|██▌       | 503/2000 [00:18<00:53, 28.00it/s]
 25%|██▌       | 506/2000 [00:18<00:53, 28.18it/s]
 25%|██▌       | 509/2000 [00:18<00:52, 28.43it/s]
 26%|██▌       | 512/2000 [00:18<00:51, 28.62it/s]
 26%|██▌       | 515/2000 [00:18<00:52, 28.50it/s]
 26%|██▌       | 518/2000 [00:18<00:51, 28.74it/s]
 26%|██▌       | 521/2000 [00:18<00:51, 28.55it/s]
 26%|██▌       | 524/2000 [00:18<00:51, 28.54it/s]
 26%|██▋       | 527/2000 [00:19<00:52, 28.31it/s]
 26%|██▋       | 530/2000 [00:19<00:51, 28.51it/s]
 27%|██▋       | 533/2000 [00:19<00:51, 28.49it/s]
 27%|██▋       | 536/2000 [00:19<00:51, 28.34it/s]
 27%|██▋       | 539/2000 [00:19<00:51, 28.24it/s]
 27%|██▋       | 542/2000 [00:19<00:51, 28.34it/s]
 27%|██▋       | 545/2000 [00:19<00:51, 28.28it/s]
 27%|██▋       | 548/2000 [00:19<00:51, 28.35it/s]
 28%|██▊       | 551/2000 [00:19<00:50, 28.42it/s]
 28%|██▊       | 554/2000 [00:19<00:51, 28.28it/s]
 28%|██▊       | 557/2000 [00:20<00:51, 28.20it/s]
 28%|██▊       | 560/2000 [00:20<00:50, 28.63it/s]
 28%|██▊       | 563/2000 [00:20<00:50, 28.50it/s]
 28%|██▊       | 566/2000 [00:20<00:50, 28.59it/s]
 28%|██▊       | 569/2000 [00:20<00:50, 28.25it/s]
 29%|██▊       | 572/2000 [00:20<00:50, 28.03it/s]
 29%|██▉       | 575/2000 [00:20<00:51, 27.71it/s]
 29%|██▉       | 578/2000 [00:20<00:51, 27.83it/s]
 29%|██▉       | 581/2000 [00:20<00:50, 27.98it/s]
 29%|██▉       | 584/2000 [00:21<00:50, 28.22it/s]
 29%|██▉       | 587/2000 [00:21<00:49, 28.29it/s]
 30%|██▉       | 590/2000 [00:21<00:50, 28.08it/s]
 30%|██▉       | 593/2000 [00:21<00:50, 27.72it/s]
 30%|██▉       | 596/2000 [00:21<00:50, 27.91it/s]
 30%|██▉       | 599/2000 [00:21<00:50, 27.70it/s]
 30%|███       | 602/2000 [00:21<00:50, 27.52it/s]
 30%|███       | 605/2000 [00:21<00:50, 27.55it/s]
 30%|███       | 608/2000 [00:21<00:50, 27.45it/s]
 31%|███       | 611/2000 [00:22<00:50, 27.48it/s]
 31%|███       | 614/2000 [00:22<00:50, 27.54it/s]
 31%|███       | 617/2000 [00:22<00:50, 27.60it/s]
 31%|███       | 620/2000 [00:22<00:49, 27.62it/s]
 31%|███       | 623/2000 [00:22<00:50, 27.39it/s]
 31%|███▏      | 626/2000 [00:22<00:50, 27.26it/s]
 31%|███▏      | 629/2000 [00:22<00:50, 27.33it/s]
 32%|███▏      | 632/2000 [00:22<00:49, 27.46it/s]
 32%|███▏      | 635/2000 [00:22<00:49, 27.35it/s]
 32%|███▏      | 638/2000 [00:22<00:50, 27.13it/s]
 32%|███▏      | 641/2000 [00:23<00:49, 27.44it/s]
 32%|███▏      | 644/2000 [00:23<00:50, 27.08it/s]
 32%|███▏      | 647/2000 [00:23<00:49, 27.40it/s]
 32%|███▎      | 650/2000 [00:23<00:49, 27.34it/s]
 33%|███▎      | 653/2000 [00:23<00:48, 27.61it/s]
 33%|███▎      | 656/2000 [00:23<00:48, 27.90it/s]
 33%|███▎      | 659/2000 [00:23<00:47, 27.98it/s]
 33%|███▎      | 662/2000 [00:23<00:48, 27.59it/s]
 33%|███▎      | 665/2000 [00:23<00:48, 27.81it/s]
 33%|███▎      | 668/2000 [00:24<00:47, 27.99it/s]
 34%|███▎      | 671/2000 [00:24<00:47, 28.11it/s]
 34%|███▎      | 674/2000 [00:24<00:46, 28.53it/s]
 34%|███▍      | 677/2000 [00:24<00:46, 28.64it/s]
 34%|███▍      | 680/2000 [00:24<00:46, 28.53it/s]
 34%|███▍      | 683/2000 [00:24<00:45, 28.65it/s]
 34%|███▍      | 686/2000 [00:24<00:46, 28.54it/s]
 34%|███▍      | 689/2000 [00:24<00:45, 28.57it/s]
 35%|███▍      | 692/2000 [00:24<00:45, 28.78it/s]
 35%|███▍      | 695/2000 [00:25<00:45, 28.76it/s]
 35%|███▍      | 699/2000 [00:25<00:44, 29.43it/s]
 35%|███▌      | 703/2000 [00:25<00:42, 30.33it/s]
 35%|███▌      | 707/2000 [00:25<00:42, 30.52it/s]
 36%|███▌      | 711/2000 [00:25<00:43, 29.96it/s]
 36%|███▌      | 714/2000 [00:25<00:43, 29.27it/s]
 36%|███▌      | 717/2000 [00:25<00:43, 29.37it/s]
 36%|███▌      | 721/2000 [00:25<00:43, 29.62it/s]
 36%|███▌      | 724/2000 [00:25<00:43, 29.50it/s]
 36%|███▋      | 727/2000 [00:26<00:42, 29.61it/s]
 37%|███▋      | 731/2000 [00:26<00:42, 30.13it/s]
 37%|███▋      | 735/2000 [00:26<00:42, 29.66it/s]
 37%|███▋      | 739/2000 [00:26<00:42, 29.87it/s]
 37%|███▋      | 743/2000 [00:26<00:41, 30.27it/s]
 37%|███▋      | 747/2000 [00:26<00:40, 30.82it/s]
 38%|███▊      | 751/2000 [00:26<00:40, 30.76it/s]
 38%|███▊      | 755/2000 [00:26<00:40, 30.66it/s]
 38%|███▊      | 759/2000 [00:27<00:40, 30.75it/s]
 38%|███▊      | 763/2000 [00:27<00:40, 30.80it/s]
 38%|███▊      | 767/2000 [00:27<00:39, 31.20it/s]
 39%|███▊      | 771/2000 [00:27<00:39, 30.98it/s]
 39%|███▉      | 775/2000 [00:27<00:39, 31.14it/s]
 39%|███▉      | 779/2000 [00:27<00:39, 31.01it/s]
 39%|███▉      | 783/2000 [00:27<00:38, 31.66it/s]
 39%|███▉      | 787/2000 [00:28<00:38, 31.65it/s]
 40%|███▉      | 791/2000 [00:28<00:37, 32.21it/s]
 40%|███▉      | 795/2000 [00:28<00:37, 32.04it/s]
 40%|███▉      | 799/2000 [00:28<00:36, 32.79it/s]
 40%|████      | 803/2000 [00:28<00:35, 33.56it/s]
 40%|████      | 807/2000 [00:28<00:35, 33.70it/s]
 41%|████      | 811/2000 [00:28<00:35, 33.53it/s]
 41%|████      | 815/2000 [00:28<00:34, 34.03it/s]
 41%|████      | 819/2000 [00:28<00:34, 34.25it/s]
 41%|████      | 823/2000 [00:29<00:34, 34.26it/s]
 41%|████▏     | 827/2000 [00:29<00:33, 34.58it/s]
 42%|████▏     | 831/2000 [00:29<00:33, 35.12it/s]
 42%|████▏     | 835/2000 [00:29<00:32, 35.51it/s]
 42%|████▏     | 839/2000 [00:29<00:33, 35.13it/s]
 42%|████▏     | 843/2000 [00:29<00:32, 35.38it/s]
 42%|████▏     | 847/2000 [00:29<00:31, 36.62it/s]
 43%|████▎     | 851/2000 [00:29<00:32, 35.69it/s]
 43%|████▎     | 855/2000 [00:29<00:32, 35.44it/s]
 43%|████▎     | 859/2000 [00:30<00:32, 35.45it/s]
 43%|████▎     | 863/2000 [00:30<00:31, 35.91it/s]
 43%|████▎     | 867/2000 [00:30<00:31, 35.88it/s]
 44%|████▎     | 872/2000 [00:30<00:30, 37.00it/s]
 44%|████▍     | 877/2000 [00:30<00:29, 38.48it/s]
 44%|████▍     | 881/2000 [00:30<00:29, 38.54it/s]
 44%|████▍     | 885/2000 [00:30<00:28, 38.83it/s]
 44%|████▍     | 890/2000 [00:30<00:27, 39.75it/s]
 45%|████▍     | 894/2000 [00:30<00:28, 39.08it/s]
 45%|████▍     | 898/2000 [00:31<00:28, 38.23it/s]
 45%|████▌     | 902/2000 [00:31<00:28, 37.98it/s]
 45%|████▌     | 906/2000 [00:31<00:28, 37.89it/s]
 46%|████▌     | 910/2000 [00:31<00:28, 38.41it/s]
 46%|████▌     | 915/2000 [00:31<00:27, 39.35it/s]
 46%|████▌     | 919/2000 [00:31<00:27, 38.89it/s]
 46%|████▌     | 923/2000 [00:31<00:27, 38.88it/s]
 46%|████▋     | 927/2000 [00:31<00:27, 39.18it/s]
 47%|████▋     | 931/2000 [00:31<00:27, 39.24it/s]
 47%|████▋     | 935/2000 [00:32<00:27, 38.53it/s]
 47%|████▋     | 939/2000 [00:32<00:28, 37.68it/s]
 47%|████▋     | 943/2000 [00:32<00:28, 37.07it/s]
 47%|████▋     | 947/2000 [00:32<00:28, 36.85it/s]
 48%|████▊     | 951/2000 [00:32<00:28, 37.10it/s]
 48%|████▊     | 955/2000 [00:32<00:28, 36.35it/s]
 48%|████▊     | 959/2000 [00:32<00:28, 36.38it/s]
 48%|████▊     | 963/2000 [00:32<00:28, 36.24it/s]
 48%|████▊     | 967/2000 [00:32<00:28, 36.52it/s]
 49%|████▊     | 971/2000 [00:33<00:28, 36.70it/s]
 49%|████▉     | 975/2000 [00:33<00:28, 36.43it/s]
 49%|████▉     | 979/2000 [00:33<00:28, 36.19it/s]
 49%|████▉     | 984/2000 [00:33<00:27, 37.38it/s]
 49%|████▉     | 988/2000 [00:33<00:27, 37.12it/s]
 50%|████▉     | 992/2000 [00:33<00:27, 36.64it/s]
 50%|████▉     | 996/2000 [00:33<00:27, 36.74it/s]
 50%|█████     | 1000/2000 [00:33<00:26, 37.37it/s]
 50%|█████     | 1004/2000 [00:33<00:26, 37.48it/s]
 50%|█████     | 1008/2000 [00:34<00:26, 37.19it/s]
 51%|█████     | 1012/2000 [00:34<00:26, 37.07it/s]
 51%|█████     | 1016/2000 [00:34<00:26, 37.61it/s]
 51%|█████     | 1020/2000 [00:34<00:25, 37.79it/s]
 51%|█████     | 1024/2000 [00:34<00:26, 37.44it/s]
 51%|█████▏    | 1028/2000 [00:34<00:26, 36.04it/s]
 52%|█████▏    | 1032/2000 [00:34<00:26, 36.18it/s]
 52%|█████▏    | 1036/2000 [00:34<00:26, 36.67it/s]
 52%|█████▏    | 1040/2000 [00:34<00:26, 36.72it/s]
 52%|█████▏    | 1044/2000 [00:34<00:25, 37.15it/s]
 52%|█████▏    | 1048/2000 [00:35<00:26, 36.47it/s]
 53%|█████▎    | 1052/2000 [00:35<00:26, 36.32it/s]
 53%|█████▎    | 1056/2000 [00:35<00:25, 36.66it/s]
 53%|█████▎    | 1060/2000 [00:35<00:26, 35.98it/s]
 53%|█████▎    | 1064/2000 [00:35<00:25, 36.47it/s]
 53%|█████▎    | 1068/2000 [00:35<00:26, 35.30it/s]
 54%|█████▎    | 1072/2000 [00:35<00:25, 36.55it/s]
 54%|█████▍    | 1077/2000 [00:35<00:24, 38.18it/s]
 54%|█████▍    | 1081/2000 [00:36<00:24, 37.99it/s]
 54%|█████▍    | 1085/2000 [00:36<00:24, 37.61it/s]
 54%|█████▍    | 1089/2000 [00:36<00:24, 37.00it/s]
 55%|█████▍    | 1093/2000 [00:36<00:24, 36.44it/s]
 55%|█████▍    | 1097/2000 [00:36<00:24, 37.06it/s]
 55%|█████▌    | 1101/2000 [00:36<00:24, 37.21it/s]
 55%|█████▌    | 1106/2000 [00:36<00:23, 38.31it/s]
 56%|█████▌    | 1110/2000 [00:36<00:23, 38.15it/s]
 56%|█████▌    | 1115/2000 [00:36<00:22, 39.16it/s]
 56%|█████▌    | 1119/2000 [00:37<00:22, 38.66it/s]
 56%|█████▌    | 1124/2000 [00:37<00:22, 39.38it/s]
 56%|█████▋    | 1129/2000 [00:37<00:21, 40.11it/s]
 57%|█████▋    | 1134/2000 [00:37<00:21, 40.17it/s]
 57%|█████▋    | 1139/2000 [00:37<00:21, 39.39it/s]
 57%|█████▋    | 1144/2000 [00:37<00:21, 40.33it/s]
 57%|█████▋    | 1149/2000 [00:37<00:21, 39.45it/s]
 58%|█████▊    | 1153/2000 [00:37<00:21, 39.28it/s]
 58%|█████▊    | 1157/2000 [00:37<00:21, 38.97it/s]
 58%|█████▊    | 1161/2000 [00:38<00:21, 39.06it/s]
 58%|█████▊    | 1165/2000 [00:38<00:21, 38.55it/s]
 58%|█████▊    | 1169/2000 [00:38<00:22, 37.70it/s]
 59%|█████▊    | 1174/2000 [00:38<00:21, 38.12it/s]
 59%|█████▉    | 1178/2000 [00:38<00:22, 36.89it/s]
 59%|█████▉    | 1183/2000 [00:38<00:21, 38.72it/s]
 59%|█████▉    | 1188/2000 [00:38<00:20, 39.17it/s]
 60%|█████▉    | 1192/2000 [00:38<00:20, 39.07it/s]
 60%|█████▉    | 1196/2000 [00:38<00:21, 38.19it/s]
 60%|██████    | 1200/2000 [00:39<00:21, 37.74it/s]
 60%|██████    | 1204/2000 [00:39<00:20, 38.24it/s]
 60%|██████    | 1209/2000 [00:39<00:20, 39.24it/s]
 61%|██████    | 1213/2000 [00:39<00:20, 38.48it/s]
 61%|██████    | 1218/2000 [00:39<00:19, 39.12it/s]
 61%|██████    | 1223/2000 [00:39<00:19, 40.27it/s]
 61%|██████▏   | 1228/2000 [00:39<00:19, 40.26it/s]
 62%|██████▏   | 1233/2000 [00:39<00:18, 41.43it/s]
 62%|██████▏   | 1238/2000 [00:40<00:17, 42.45it/s]
 62%|██████▏   | 1243/2000 [00:40<00:18, 41.97it/s]
 62%|██████▏   | 1248/2000 [00:40<00:18, 41.49it/s]
 63%|██████▎   | 1253/2000 [00:40<00:17, 41.75it/s]
 63%|██████▎   | 1258/2000 [00:40<00:17, 41.65it/s]
 63%|██████▎   | 1263/2000 [00:40<00:17, 41.64it/s]
 63%|██████▎   | 1268/2000 [00:40<00:17, 41.29it/s]
 64%|██████▎   | 1273/2000 [00:40<00:17, 40.84it/s]
 64%|██████▍   | 1278/2000 [00:40<00:17, 40.86it/s]
 64%|██████▍   | 1283/2000 [00:41<00:16, 42.20it/s]
 64%|██████▍   | 1288/2000 [00:41<00:16, 42.23it/s]
 65%|██████▍   | 1293/2000 [00:41<00:16, 41.93it/s]
 65%|██████▍   | 1298/2000 [00:41<00:16, 42.11it/s]
 65%|██████▌   | 1303/2000 [00:41<00:16, 42.44it/s]
 65%|██████▌   | 1308/2000 [00:41<00:16, 41.66it/s]
 66%|██████▌   | 1313/2000 [00:41<00:16, 41.14it/s]
 66%|██████▌   | 1318/2000 [00:41<00:16, 40.53it/s]
 66%|██████▌   | 1323/2000 [00:42<00:16, 40.73it/s]
 66%|██████▋   | 1328/2000 [00:42<00:16, 41.75it/s]
 67%|██████▋   | 1333/2000 [00:42<00:16, 41.12it/s]
 67%|██████▋   | 1338/2000 [00:42<00:16, 41.18it/s]
 67%|██████▋   | 1343/2000 [00:42<00:16, 40.84it/s]
 67%|██████▋   | 1348/2000 [00:42<00:15, 41.83it/s]
 68%|██████▊   | 1353/2000 [00:42<00:15, 41.68it/s]
 68%|██████▊   | 1358/2000 [00:42<00:15, 42.05it/s]
 68%|██████▊   | 1363/2000 [00:43<00:15, 42.12it/s]
 68%|██████▊   | 1368/2000 [00:43<00:14, 42.57it/s]
 69%|██████▊   | 1373/2000 [00:43<00:14, 43.50it/s]
 69%|██████▉   | 1378/2000 [00:43<00:14, 42.88it/s]
 69%|██████▉   | 1383/2000 [00:43<00:14, 43.65it/s]
 69%|██████▉   | 1388/2000 [00:43<00:14, 41.85it/s]
 70%|██████▉   | 1393/2000 [00:43<00:14, 41.65it/s]
 70%|██████▉   | 1398/2000 [00:43<00:14, 41.68it/s]
 70%|███████   | 1403/2000 [00:43<00:14, 40.53it/s]
 70%|███████   | 1408/2000 [00:44<00:14, 41.20it/s]
 71%|███████   | 1413/2000 [00:44<00:14, 41.60it/s]
 71%|███████   | 1418/2000 [00:44<00:13, 41.71it/s]
 71%|███████   | 1423/2000 [00:44<00:13, 42.82it/s]
 71%|███████▏  | 1428/2000 [00:44<00:13, 43.30it/s]
 72%|███████▏  | 1433/2000 [00:44<00:13, 42.38it/s]
 72%|███████▏  | 1438/2000 [00:44<00:13, 42.14it/s]
 72%|███████▏  | 1443/2000 [00:44<00:13, 42.42it/s]
 72%|███████▏  | 1448/2000 [00:45<00:12, 42.70it/s]
 73%|███████▎  | 1453/2000 [00:45<00:12, 42.33it/s]
 73%|███████▎  | 1458/2000 [00:45<00:12, 43.14it/s]
 73%|███████▎  | 1463/2000 [00:45<00:12, 42.85it/s]
 73%|███████▎  | 1468/2000 [00:45<00:12, 42.40it/s]
 74%|███████▎  | 1473/2000 [00:45<00:12, 42.22it/s]
 74%|███████▍  | 1478/2000 [00:45<00:12, 42.10it/s]
 74%|███████▍  | 1483/2000 [00:45<00:11, 43.15it/s]
 74%|███████▍  | 1488/2000 [00:45<00:11, 44.70it/s]
 75%|███████▍  | 1493/2000 [00:46<00:11, 43.61it/s]
 75%|███████▍  | 1498/2000 [00:46<00:11, 44.06it/s]
 75%|███████▌  | 1503/2000 [00:46<00:11, 43.50it/s]
 75%|███████▌  | 1508/2000 [00:46<00:11, 43.45it/s]
 76%|███████▌  | 1513/2000 [00:46<00:11, 43.88it/s]
 76%|███████▌  | 1518/2000 [00:46<00:11, 43.43it/s]
 76%|███████▌  | 1523/2000 [00:46<00:11, 43.25it/s]
 76%|███████▋  | 1528/2000 [00:46<00:10, 43.39it/s]
 77%|███████▋  | 1533/2000 [00:46<00:10, 44.05it/s]
 77%|███████▋  | 1538/2000 [00:47<00:10, 44.32it/s]
 77%|███████▋  | 1543/2000 [00:47<00:10, 43.78it/s]
 77%|███████▋  | 1548/2000 [00:47<00:10, 44.61it/s]
 78%|███████▊  | 1553/2000 [00:47<00:10, 43.54it/s]
 78%|███████▊  | 1558/2000 [00:47<00:10, 43.55it/s]
 78%|███████▊  | 1563/2000 [00:47<00:09, 43.73it/s]
 78%|███████▊  | 1568/2000 [00:47<00:09, 43.80it/s]
 79%|███████▊  | 1573/2000 [00:47<00:09, 44.19it/s]
 79%|███████▉  | 1578/2000 [00:48<00:09, 43.14it/s]
 79%|███████▉  | 1583/2000 [00:48<00:09, 43.02it/s]
 79%|███████▉  | 1588/2000 [00:48<00:09, 42.31it/s]
 80%|███████▉  | 1593/2000 [00:48<00:09, 42.25it/s]
 80%|███████▉  | 1598/2000 [00:48<00:09, 43.09it/s]
 80%|████████  | 1603/2000 [00:48<00:09, 43.69it/s]
 80%|████████  | 1608/2000 [00:48<00:09, 41.64it/s]
 81%|████████  | 1613/2000 [00:48<00:09, 41.42it/s]
 81%|████████  | 1618/2000 [00:48<00:09, 40.74it/s]
 81%|████████  | 1623/2000 [00:49<00:09, 40.46it/s]
 81%|████████▏ | 1628/2000 [00:49<00:08, 41.57it/s]
 82%|████████▏ | 1633/2000 [00:49<00:08, 41.36it/s]
 82%|████████▏ | 1638/2000 [00:49<00:08, 41.99it/s]
 82%|████████▏ | 1643/2000 [00:49<00:08, 41.35it/s]
 82%|████████▏ | 1648/2000 [00:49<00:08, 41.32it/s]
 83%|████████▎ | 1653/2000 [00:49<00:08, 42.04it/s]
 83%|████████▎ | 1658/2000 [00:49<00:07, 43.44it/s]
 83%|████████▎ | 1663/2000 [00:50<00:07, 44.25it/s]
 83%|████████▎ | 1668/2000 [00:50<00:07, 43.53it/s]
 84%|████████▎ | 1673/2000 [00:50<00:07, 42.29it/s]
 84%|████████▍ | 1678/2000 [00:50<00:07, 43.22it/s]
 84%|████████▍ | 1683/2000 [00:50<00:07, 44.15it/s]
 84%|████████▍ | 1688/2000 [00:50<00:07, 43.54it/s]
 85%|████████▍ | 1693/2000 [00:50<00:06, 44.07it/s]
 85%|████████▍ | 1698/2000 [00:50<00:07, 43.08it/s]
 85%|████████▌ | 1703/2000 [00:50<00:06, 44.26it/s]
 85%|████████▌ | 1708/2000 [00:51<00:06, 43.46it/s]
 86%|████████▌ | 1713/2000 [00:51<00:06, 42.74it/s]
 86%|████████▌ | 1718/2000 [00:51<00:06, 42.47it/s]
 86%|████████▌ | 1723/2000 [00:51<00:06, 43.31it/s]
 86%|████████▋ | 1728/2000 [00:51<00:06, 44.56it/s]
 87%|████████▋ | 1733/2000 [00:51<00:06, 43.78it/s]
 87%|████████▋ | 1738/2000 [00:51<00:05, 43.93it/s]
 87%|████████▋ | 1743/2000 [00:51<00:05, 43.98it/s]
 87%|████████▋ | 1748/2000 [00:51<00:05, 43.63it/s]
 88%|████████▊ | 1753/2000 [00:52<00:05, 43.03it/s]
 88%|████████▊ | 1758/2000 [00:52<00:05, 40.72it/s]
 88%|████████▊ | 1763/2000 [00:52<00:05, 41.60it/s]
 88%|████████▊ | 1768/2000 [00:52<00:05, 41.85it/s]
 89%|████████▊ | 1773/2000 [00:52<00:05, 42.74it/s]
 89%|████████▉ | 1778/2000 [00:52<00:05, 41.85it/s]
 89%|████████▉ | 1783/2000 [00:52<00:05, 43.19it/s]
 89%|████████▉ | 1788/2000 [00:52<00:04, 43.29it/s]
 90%|████████▉ | 1793/2000 [00:53<00:04, 44.95it/s]
 90%|████████▉ | 1798/2000 [00:53<00:04, 44.78it/s]
 90%|█████████ | 1803/2000 [00:53<00:04, 43.81it/s]
 90%|█████████ | 1808/2000 [00:53<00:04, 43.19it/s]
 91%|█████████ | 1813/2000 [00:53<00:04, 43.01it/s]
 91%|█████████ | 1818/2000 [00:53<00:04, 43.95it/s]
 91%|█████████ | 1823/2000 [00:53<00:04, 44.06it/s]
 91%|█████████▏| 1828/2000 [00:53<00:03, 43.57it/s]
 92%|█████████▏| 1833/2000 [00:53<00:03, 44.09it/s]
 92%|█████████▏| 1838/2000 [00:54<00:03, 43.10it/s]
 92%|█████████▏| 1843/2000 [00:54<00:03, 42.82it/s]
 92%|█████████▏| 1848/2000 [00:54<00:03, 43.50it/s]
 93%|█████████▎| 1853/2000 [00:54<00:03, 43.01it/s]
 93%|█████████▎| 1858/2000 [00:54<00:03, 42.98it/s]
 93%|█████████▎| 1863/2000 [00:54<00:03, 41.76it/s]
 93%|█████████▎| 1868/2000 [00:54<00:03, 42.01it/s]
 94%|█████████▎| 1873/2000 [00:54<00:03, 41.31it/s]
 94%|█████████▍| 1878/2000 [00:55<00:02, 42.55it/s]
 94%|█████████▍| 1883/2000 [00:55<00:02, 43.54it/s]
 94%|█████████▍| 1888/2000 [00:55<00:02, 43.27it/s]
 95%|█████████▍| 1893/2000 [00:55<00:02, 44.34it/s]
 95%|█████████▍| 1898/2000 [00:55<00:02, 44.10it/s]
 95%|█████████▌| 1903/2000 [00:55<00:02, 44.26it/s]
 95%|█████████▌| 1908/2000 [00:55<00:02, 44.13it/s]
 96%|█████████▌| 1913/2000 [00:55<00:01, 43.76it/s]
 96%|█████████▌| 1918/2000 [00:55<00:01, 43.87it/s]
 96%|█████████▌| 1923/2000 [00:56<00:01, 44.45it/s]
 96%|█████████▋| 1928/2000 [00:56<00:01, 43.83it/s]
 97%|█████████▋| 1933/2000 [00:56<00:01, 44.42it/s]
 97%|█████████▋| 1938/2000 [00:56<00:01, 43.41it/s]
 97%|█████████▋| 1943/2000 [00:56<00:01, 43.76it/s]
 97%|█████████▋| 1948/2000 [00:56<00:01, 43.29it/s]
 98%|█████████▊| 1953/2000 [00:56<00:01, 44.09it/s]
 98%|█████████▊| 1958/2000 [00:56<00:00, 43.83it/s]
 98%|█████████▊| 1963/2000 [00:56<00:00, 42.90it/s]
 98%|█████████▊| 1968/2000 [00:57<00:00, 43.51it/s]
 99%|█████████▊| 1973/2000 [00:57<00:00, 43.80it/s]
 99%|█████████▉| 1978/2000 [00:57<00:00, 44.92it/s]
 99%|█████████▉| 1983/2000 [00:57<00:00, 44.13it/s]
 99%|█████████▉| 1988/2000 [00:57<00:00, 43.55it/s]
100%|█████████▉| 1993/2000 [00:57<00:00, 44.74it/s]
100%|█████████▉| 1998/2000 [00:57<00:00, 44.95it/s]
100%|██████████| 2000/2000 [00:57<00:00, 34.61it/s]
sampler = inv_result_fixed_d_sampler.sampler
az_idata = az.from_emcee(sampler, var_names=labels)
az_idata.get("posterior")
<xarray.DataTree 'posterior'>
Group: /posterior
    Dimensions:  (draw: 2000, chain: 40)
    Coordinates:
      * draw     (draw) int64 16kB 0 1 2 3 4 5 6 ... 1994 1995 1996 1997 1998 1999
      * chain    (chain) int64 320B 0 1 2 3 4 5 6 7 8 ... 31 32 33 34 35 36 37 38 39
    Data variables: (12/17)
        v0       (draw, chain) float64 640kB 3.442 3.565 2.64 ... 3.397 3.403 3.399
        t0       (draw, chain) float64 640kB 14.87 14.8 15.96 ... 19.81 19.5 19.21
        v1       (draw, chain) float64 640kB 3.46 3.442 3.666 ... 3.646 3.65 3.664
        t1       (draw, chain) float64 640kB 13.8 15.17 14.99 ... 15.33 15.54 16.06
        v2       (draw, chain) float64 640kB 3.545 4.637 4.238 ... 4.255 4.23 4.28
        t2       (draw, chain) float64 640kB 14.77 15.8 14.9 ... 5.83 5.113 7.897
        ...       ...
        t5       (draw, chain) float64 640kB 14.66 15.36 15.02 ... 23.98 28.18 29.38
        v6       (draw, chain) float64 640kB 5.238 3.977 4.454 ... 4.379 4.305 4.319
        t6       (draw, chain) float64 640kB 14.94 14.27 15.41 ... 18.69 20.54 29.36
        v7       (draw, chain) float64 640kB 4.889 4.216 3.019 ... 4.412 4.362 4.324
        t7       (draw, chain) float64 640kB 15.6 15.14 16.34 ... 19.47 14.71 16.27
        v8       (draw, chain) float64 640kB 5.56 4.319 4.361 ... 4.468 4.542 4.565
    Attributes:
        created_at:                 2026-05-25T05:53:10.972404+00:00
        creation_library:           ArviZ
        creation_library_version:   1.1.0
        creation_library_language:  Python
        inference_library:          emcee
        inference_library_version:  3.1.6
        sample_dims:                ['draw', 'chain']


flat_samples = sampler.get_chain(discard=500, thin=500, flat=True)
rand_indices = np.random.randint(len(flat_samples), size=100)

_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 3, 3]})

ax1.set_ylim(170)

# plot samples and data predictions from samples
for idx in rand_indices:
    sample = flat_samples[idx]
    plot_model(sample, ax=ax1, alpha=0.2, lw=0.5, color="gray")
    plot_sw_data(forward_sw(sample, periods), periods,
                 ax=ax2, alpha=0.2, lw=0.5, color="gray")
    plot_rf_data(forward_rf(sample), rf_times,
                 ax=ax3, alpha=0.2, lw=0.5, color="gray")

# add labels to samples
sample_0 = flat_samples[rand_indices[0]]
plot_model(sample_0, ax=ax1, alpha=0.5, lw=0.5, color="gray", label="samples")
plot_sw_data(forward_sw(sample_0, periods), periods, ax=ax2,
             alpha=0.5, lw=0.5, color="gray", label="rayleigh_dpred from samples")
plot_rf_data(forward_rf(sample_0), rf_times, ax=ax3,
             alpha=0.5, lw=0.5, color="gray", label="rf_dpred from samples")

# plot true model and data observations
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="r", s=4,
          label="rayleigh_dobs")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="r", s=2,
          label="rf_dobs")

# plot damped optimisation result
plot_model(inv_res_optimiser.model, ax=ax1, alpha=1, color="green",
           label="damped solution")
plot_sw_data(forward_sw(inv_res_optimiser_no_reg.model, periods),
             periods, ax=ax2, color="green",
             label="rayleigh_dpred from damped solution")
plot_rf_data(forward_rf(inv_res_optimiser.model), rf_times,
             ax=ax3, color="green",
             label="rf_dpred from damped solution")

# plot initial model for dampied optimsiation
plot_model(init_model, ax=ax1, alpha=1, color="purple",
           label="initial model for damped solution")
plot_sw_data(forward_sw(init_model, periods), periods, ax=ax2, color="purple",
             label="rayleigh_dpred from initial model for damped solution")
plot_rf_data(forward_rf(init_model), rf_times, ax=ax3, color="purple",
             label="rf_dpred from initial model for damped solution")

ax1.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax2.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax3.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax1.grid()
ax2.grid()
ax3.grid()

plt.tight_layout()
pc = az.plot_trace_dist(
    az_idata,
    visuals={"xlabel_trace": False, "trace": {"color": "C0", "lw": 0.5}, "dist": {"color": "C0", "lw": 0.5}},
    figure_kwargs={"figsize": (12, 40), "constrained_layout": True},
)

n_vars = len(az_idata.posterior.data_vars)
var_names = list(az_idata.posterior.data_vars)
for i in range(n_vars):
    ax1 = pc.iget_target(i, 0)
    ax2 = pc.iget_target(i, 1)
    ax1.axvline(true_model[i], linestyle="dotted", color="red")
    ax1.set_title(var_names[i])
    ax1.set_xlabel("parameter value")
    ax1.set_ylabel("density value")
    ax2.axhline(true_model[i], linestyle="dotted", color="red")
    ax2.set_title(var_names[i])
    ax2.set_xlabel("number of iterations")
    ax2.set_ylabel("parameter value")
    ax2.margins(x=0)
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")
/usr/local/lib/python3.13/site-packages/arviz_stats/base/density.py:671: UserWarning: Your data appears to have a single value or no finite values
  warnings.warn("Your data appears to have a single value or no finite values")

Trans-dimensional sampling#

Prepare utilities for trans-d sampling

def fwd_rayleigh_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, periods)

def fwd_rf_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_rf(model)
targets = [
    bayesbay.Target("rayleigh", rayleigh_dobs, covariance_mat_inv=1 / RAYLEIGH_STD**2),
    bayesbay.Target("rf", rf_dobs, covariance_mat_inv=1 / RF_STD**2),
]
forward_funcs = [fwd_rayleigh_for_bayesbay, fwd_rf_for_bayesbay]

my_log_likelihood = bayesbay.LogLikelihood(targets, forward_funcs)
/home/kitc/actions-runner/_work/cofi/cofi/docs/source/examples/scripts_synth_data/sw_rf_joint_synthetic.py:1005: DeprecationWarning: The 'Target' class has been moved to the 'likelihood' module. Please use 'from bayesbay.likelihood import Target' instead.
  bayesbay.Target("rayleigh", rayleigh_dobs, covariance_mat_inv=1 / RAYLEIGH_STD**2),
/home/kitc/actions-runner/_work/cofi/cofi/docs/source/examples/scripts_synth_data/sw_rf_joint_synthetic.py:1006: DeprecationWarning: The 'Target' class has been moved to the 'likelihood' module. Please use 'from bayesbay.likelihood import Target' instead.
  bayesbay.Target("rf", rf_dobs, covariance_mat_inv=1 / RF_STD**2),
/home/kitc/actions-runner/_work/cofi/cofi/docs/source/examples/scripts_synth_data/sw_rf_joint_synthetic.py:1010: DeprecationWarning: The 'LogLikelihood' class has been moved to the 'likelihood' module. Please use 'from bayesbay.likelihood import LogLikelihood' instead.
  my_log_likelihood = bayesbay.LogLikelihood(targets, forward_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_funcs
n_chains=12
walkers_start = []
for i in range(n_chains):
    walkers_start.append(parameterization.initialize())

Define ``InversionOptions``

inv_options_trans_d = cofi.InversionOptions()
inv_options_trans_d.set_tool("bayesbay")
inv_options_trans_d.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=2_000,
    burnin_iterations=1_000,
    verbose=False,
    save_every=200,
)

Define ``Inversion`` and run

inversion_trans_d_sampler = cofi.Inversion(joint_problem, inv_options_trans_d)
inv_res_trans_d_sampler = inversion_trans_d_sampler.run()
saved_states = inv_res_trans_d_sampler.models
samples_voronoi = saved_states["voronoi.discretization"]
samples_vs = saved_states["voronoi.vs"]
interp_depths = np.arange(150, dtype=float)
rand_indices = np.random.randint(len(samples_voronoi), size=100)

_, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), gridspec_kw={'width_ratios': [1, 3, 3]})

ax1.set_ylim(170)

# plot samples and data predictions from samples
for idx in rand_indices:
    sample_voronoi = form_voronoi_model(samples_voronoi[idx], samples_vs[idx])
    sample = voronoi_to_layercake(sample_voronoi)
    plot_model(sample, ax=ax1, alpha=0.2, lw=0.5, color="gray")
    plot_sw_data(forward_sw(sample, periods), periods,
                 ax=ax2, alpha=0.2, lw=0.5, color="gray")
    plot_rf_data(forward_rf(sample), rf_times,
                 ax=ax3, alpha=0.2, lw=0.5, color="gray")

# add labels to samples
sample_0_voronoi = form_voronoi_model(samples_voronoi[0], samples_vs[0])
sample_0 = voronoi_to_layercake(sample_0_voronoi)
plot_model(sample_0, ax=ax1, alpha=0.2, lw=0.5, color="gray", label="samples")
plot_sw_data(forward_sw(sample_0, periods), periods, ax=ax2,
             alpha=0.2, lw=0.5, color="gray", label="rayleigh_dpred from samples")
plot_rf_data(forward_rf(sample_0), rf_times, ax=ax3,
             alpha=0.2, lw=0.5, color="gray", label="rf_dpred from samples")

# plot true model and data observations
plot_model(true_model, ax=ax1, alpha=1, color="r", label="true model")
plot_sw_data(rayleigh_dobs, periods, ax=ax2, scatter=True, color="r", s=4,
          label="rayleigh_dobs")
plot_rf_data(rf_dobs, rf_times, ax=ax3, scatter=True, color="r", s=2,
          label="rf_dobs")

# plot damped optimisation result
plot_model(inv_res_optimiser.model, ax=ax1, alpha=1, color="green",
           label="damped solution")
plot_sw_data(forward_sw(inv_res_optimiser_no_reg.model, periods),
             periods, ax=ax2, color="green",
             label="rayleigh_dpred from damped solution")
plot_rf_data(forward_rf(inv_res_optimiser.model), rf_times,
             ax=ax3, color="green",
             label="rf_dpred from damped solution")

# plot initial model for dampied optimsiation
plot_model(init_model, ax=ax1, alpha=1, color="purple",
           label="initial model for damped solution")
plot_sw_data(forward_sw(init_model, periods), periods, ax=ax2, color="purple",
             label="rayleigh_dpred from initial model for damped solution")
plot_rf_data(forward_rf(init_model), rf_times, ax=ax3, color="purple",
             label="rf_dpred from initial model for damped solution")

ax1.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax2.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax3.legend(loc="upper center", bbox_to_anchor=(0.5, -0.18))
ax1.grid()
ax2.grid()
ax3.grid()

plt.tight_layout()

Watermark#

watermark_list = ["cofi", "numpy", "matplotlib", "scipy", "bayesbay"]
for pkg in watermark_list:
    pkg_var = __import__(pkg)
    print(pkg, getattr(pkg_var, "__version__"))
cofi 0.2.11+71.gb28b5b0
numpy 2.2.6
matplotlib 3.10.9
scipy 1.17.1
bayesbay 0.3.10

sphinx_gallery_thumbnail_number = -1

Total running time of the script: (1 minutes 48.654 seconds)

Gallery generated by Sphinx-Gallery