Note
Go to the end to download the full example code.
Petrophysically guided inversion (PGI): Linear example#
We do a comparison between the classic least-squares inversion and our formulation of a petrophysically constrained inversion. We explore it through the UBC linear example.
Tikhonov Inversion##
import discretize as Mesh
import matplotlib.pyplot as plt
import numpy as np
from simpeg import (
data_misfit,
directives,
inverse_problem,
inversion,
maps,
optimization,
regularization,
simulation,
utils,
)
# Random seed for reproductibility
np.random.seed(1)
# Mesh
N = 100
mesh = Mesh.TensorMesh([N])
# Survey design parameters
nk = 20
jk = np.linspace(1.0, 60.0, nk)
p = -0.25
q = 0.25
# Physics
def g(k):
return np.exp(p * jk[k] * mesh.cell_centers_x) * np.cos(
np.pi * q * jk[k] * mesh.cell_centers_x
)
G = np.empty((nk, mesh.nC))
for i in range(nk):
G[i, :] = g(i)
# True model
mtrue = np.zeros(mesh.nC)
mtrue[mesh.cell_centers_x > 0.2] = 1.0
mtrue[mesh.cell_centers_x > 0.35] = 0.0
t = (mesh.cell_centers_x - 0.65) / 0.25
indx = np.abs(t) < 1
mtrue[indx] = -(((1 - t**2.0) ** 2.0)[indx])
mtrue = np.zeros(mesh.nC)
mtrue[mesh.cell_centers_x > 0.3] = 1.0
mtrue[mesh.cell_centers_x > 0.45] = -0.5
mtrue[mesh.cell_centers_x > 0.6] = 0
# simpeg problem and survey
prob = simulation.LinearSimulation(mesh, G=G, model_map=maps.IdentityMap())
std = 0.01
survey = prob.make_synthetic_data(mtrue, relative_error=std, add_noise=True)
# Setup the inverse problem
reg = regularization.WeightedLeastSquares(mesh, alpha_s=1.0, alpha_x=1.0)
dmis = data_misfit.L2DataMisfit(data=survey, simulation=prob)
opt = optimization.ProjectedGNCG(maxIter=10, cg_maxiter=50, cg_rtol=1e-3)
invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
directiveslist = [
directives.BetaEstimate_ByEig(beta0_ratio=1e-5),
directives.BetaSchedule(coolingFactor=10.0, coolingRate=2),
directives.TargetMisfit(),
]
inv = inversion.BaseInversion(invProb, directiveList=directiveslist)
m0 = np.zeros_like(mtrue)
mnormal = inv.run(m0)
Running inversion with SimPEG v0.26.1.dev2+g3562108fd
================================================= Projected GNCG =================================================
# beta phi_d phi_m f |proj(x-g)-x| LS iter_CG CG |Ax-b|/|b| CG |Ax-b| Comment
-----------------------------------------------------------------------------------------------------------------
0 1.81e+01 2.00e+05 0.00e+00 2.00e+05 0 inf inf
1 1.81e+01 3.37e+02 4.20e+01 1.09e+03 2.50e+06 0 13 7.48e-04 1.87e+03
2 1.81e+01 4.18e+01 4.53e+01 8.60e+02 1.87e+03 0 23 2.57e-04 4.80e-01
3 1.81e+00 1.31e+01 4.90e+01 1.02e+02 5.02e+02 0 50 2.01e+01 1.01e+04 Skip BFGS
------------------------- STOP! -------------------------
1 : |fc-fOld| = 2.2039e+01 <= tolF*(1+|f0|) = 2.0000e+04
0 : |xc-x_last| = 2.5222e-01 <= tolX*(1+|x0|) = 1.0000e-01
0 : |proj(x-g)-x| = 5.0233e+02 <= tolG = 1.0000e-01
0 : |proj(x-g)-x| = 5.0233e+02 <= 1e3*eps = 1.0000e-02
0 : maxIter = 10 <= iter = 3
------------------------- DONE! -------------------------
Petrophysically constrained inversion ##
# fit a Gaussian Mixture Model with n components
# on the true model to simulate the laboratory
# petrophysical measurements
n = 3
clf = utils.WeightedGaussianMixture(
mesh=mesh,
n_components=n,
covariance_type="full",
max_iter=100,
n_init=3,
reg_covar=5e-4,
)
clf.fit(mtrue.reshape(-1, 1))
# Petrophyically constrained regularization
reg = regularization.PGI(
gmmref=clf,
mesh=mesh,
alpha_pgi=1.0,
alpha_x=1.0,
)
# Optimization
opt = optimization.ProjectedGNCG(maxIter=20, cg_maxiter=50, cg_rtol=1e-3)
opt.remember("xc")
# Setup new inverse problem
invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
# directives
Alphas = directives.AlphasSmoothEstimate_ByEig(alpha0_ratio=10.0, verbose=True)
beta = directives.BetaEstimate_ByEig(beta0_ratio=1e-8)
betaIt = directives.PGI_BetaAlphaSchedule(
verbose=True,
coolingFactor=2.0,
warmingFactor=1.0,
tolerance=0.1,
update_rate=1,
progress=0.2,
)
targets = directives.MultiTargetMisfits(verbose=True)
petrodir = directives.PGI_UpdateParameters()
addmref = directives.PGI_AddMrefInSmooth(verbose=True)
# Setup Inversion
inv = inversion.BaseInversion(
invProb, directiveList=[Alphas, beta, petrodir, targets, addmref, betaIt]
)
# Initial model same as for WeightedLeastSquares
mcluster = inv.run(m0)
# Final Plot
fig, axes = plt.subplots(1, 3, figsize=(12 * 1.2, 4 * 1.2))
for i in range(prob.G.shape[0]):
axes[0].plot(prob.G[i, :])
axes[0].set_title("Columns of matrix G")
axes[1].hist(mtrue, bins=20, linewidth=3.0, density=True, color="k")
axes[1].set_xlabel("Model value")
axes[1].set_xlabel("Occurence")
axes[1].hist(mnormal, bins=20, density=True, color="b")
axes[1].hist(mcluster, bins=20, density=True, color="r")
axes[1].legend(["Mtrue Hist.", "L2 Model Hist.", "PGI Model Hist."])
axes[2].plot(mesh.cell_centers_x, mtrue, color="black", linewidth=3)
axes[2].plot(mesh.cell_centers_x, mnormal, color="blue")
axes[2].plot(mesh.cell_centers_x, mcluster, "r-")
axes[2].plot(mesh.cell_centers_x, invProb.reg.objfcts[0].reference_model, "r--")
axes[2].legend(("True Model", "L2 Model", "PGI Model", "Learned Mref"))
axes[2].set_ylim([-2, 2])
plt.show()

Running inversion with SimPEG v0.26.1.dev2+g3562108fd
Alpha scales: [np.float64(0.5228656196973223), np.float64(0.0)]
<class 'simpeg.regularization.pgi.PGIsmallness'>
================================================= Projected GNCG =================================================
# beta phi_d phi_m f |proj(x-g)-x| LS iter_CG CG |Ax-b|/|b| CG |Ax-b| Comment
-----------------------------------------------------------------------------------------------------------------
0 3.20e-02 2.00e+05 0.00e+00 2.00e+05 0 inf inf
1 3.20e-02 4.55e+01 3.49e+02 5.67e+01 2.50e+06 0 14 6.03e-04 1.50e+03
geophys. misfits: 45.5 (target 20.0 [False]) | smallness misfit: 2956.5 (target: 100.0 [False])
mref changed in 25 places
Beta cooling evaluation: progress: [45.5]; minimum progress targets: [160000.]
2 3.20e-02 4.52e+00 8.73e+01 7.31e+00 1.50e+03 0 36 7.51e-04 1.13e+00 Skip BFGS
geophys. misfits: 4.5 (target 20.0 [True]) | smallness misfit: 4137.5 (target: 100.0 [False])
mref changed in 4 places
Beta cooling evaluation: progress: [4.5]; minimum progress targets: [36.4]
Warming alpha_pgi to favor clustering: 4.429189638845439
3 3.20e-02 4.93e+00 1.29e+02 9.05e+00 7.36e+00 0 50 3.64e-01 2.68e+00
geophys. misfits: 4.9 (target 20.0 [True]) | smallness misfit: 1575.5 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [4.9]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 17.97843431991249
4 3.20e-02 6.08e+00 2.27e+02 1.33e+01 1.57e+01 0 50 1.13e-01 1.77e+00
geophys. misfits: 6.1 (target 20.0 [True]) | smallness misfit: 727.4 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [6.1]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 59.14654904338114
5 3.20e-02 8.02e+00 3.88e+02 2.04e+01 3.20e+01 0 50 8.36e-01 2.67e+01
geophys. misfits: 8.0 (target 20.0 [True]) | smallness misfit: 445.1 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [8.]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 147.4593842471707
6 3.20e-02 1.05e+01 6.49e+02 3.12e+01 5.94e+01 0 50 6.36e-01 3.78e+01
geophys. misfits: 10.5 (target 20.0 [True]) | smallness misfit: 348.1 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [10.5]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 280.84329770137686
7 3.20e-02 1.34e+01 9.86e+02 4.49e+01 8.18e+01 0 50 7.90e-01 6.46e+01
geophys. misfits: 13.4 (target 20.0 [True]) | smallness misfit: 301.5 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [13.4]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 418.93582934105666
8 3.20e-02 1.65e+01 1.29e+03 5.76e+01 9.59e+01 0 50 4.99e-01 4.78e+01 Skip BFGS
geophys. misfits: 16.5 (target 20.0 [True]) | smallness misfit: 273.2 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [16.5]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 508.85877442087946
9 3.20e-02 1.84e+01 1.47e+03 6.52e+01 6.56e+01 0 50 2.53e+00 1.66e+02 Skip BFGS
geophys. misfits: 18.4 (target 20.0 [True]) | smallness misfit: 260.2 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [18.4]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 554.6140245917152
10 3.20e-02 1.96e+01 1.54e+03 6.89e+01 1.68e+02 0 50 1.03e-01 1.73e+01 Skip BFGS
geophys. misfits: 19.6 (target 20.0 [True]) | smallness misfit: 252.9 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [19.6]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 567.0400864575919
11 3.20e-02 1.99e+01 1.56e+03 6.99e+01 1.89e+01 0 50 8.26e-01 1.56e+01 Skip BFGS
geophys. misfits: 19.9 (target 20.0 [True]) | smallness misfit: 250.8 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [19.9]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 569.4377050671294
12 3.20e-02 2.00e+01 1.57e+03 7.01e+01 1.57e+01 0 50 2.97e-01 4.66e+00
geophys. misfits: 20.0 (target 20.0 [True]) | smallness misfit: 250.5 (target: 100.0 [False])
mref changed in 0 places
Add mref to Smoothness. Changes in mref happened in 0.0 % of the cells
Beta cooling evaluation: progress: [20.]; minimum progress targets: [22.]
Warming alpha_pgi to favor clustering: 570.1183896719422
13 3.20e-02 2.00e+01 1.57e+03 7.02e+01 4.73e+00 0 50 3.59e+00 1.70e+01
geophys. misfits: 20.0 (target 20.0 [False]) | smallness misfit: 250.1 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.]; minimum progress targets: [22.]
14 3.20e-02 2.01e+01 1.57e+03 7.02e+01 1.70e+01 0 50 8.04e-02 1.37e+00
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
15 3.20e-02 2.01e+01 1.57e+03 7.02e+01 1.37e+00 0 50 5.76e-01 7.86e-01
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
16 3.20e-02 2.01e+01 1.57e+03 7.02e+01 7.86e-01 0 50 3.35e+00 2.63e+00
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
17 3.20e-02 2.01e+01 1.57e+03 7.02e+01 2.63e+00 0 50 3.35e-01 8.81e-01
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
18 3.20e-02 2.01e+01 1.57e+03 7.02e+01 8.81e-01 0 50 4.62e-01 4.07e-01 Skip BFGS
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
19 3.20e-02 2.01e+01 1.57e+03 7.02e+01 4.07e-01 0 50 2.00e-01 8.14e-02
geophys. misfits: 20.1 (target 20.0 [False]) | smallness misfit: 250.0 (target: 100.0 [False])
mref changed in 0 places
Beta cooling evaluation: progress: [20.1]; minimum progress targets: [22.]
------------------------- STOP! -------------------------
1 : |fc-fOld| = 8.6821e-08 <= tolF*(1+|f0|) = 2.0000e+04
1 : |xc-x_last| = 1.3537e-05 <= tolX*(1+|x0|) = 1.0000e-01
1 : |proj(x-g)-x| = 8.1375e-02 <= tolG = 1.0000e-01
0 : |proj(x-g)-x| = 8.1375e-02 <= 1e3*eps = 1.0000e-02
0 : maxIter = 20 <= iter = 19
------------------------- DONE! -------------------------
Total running time of the script: (0 minutes 10.698 seconds)
Estimated memory usage: 343 MB