Learning goals¶
- Run 1D MT inversion for the same field data that you conducted a manual parametric fitting.
import numpy as np
from simpeg.electromagnetics import natural_source as nsem
from simpeg import maps
import matplotlib.pyplot as plt
import matplotlib
from simpeg.utils import plot_1d_layer_model
from discretize import TensorMesh
from simpeg import (
maps,
data,
data_misfit,
regularization,
optimization,
inverse_problem,
inversion,
directives,
utils,
)
from mtpy import MTCollection
mc = MTCollection()
mc.open_collection("../../data/transfer_functions/yellowstone_mt_collection.h5")
from ipywidgets import widgets, interact
station_names = mc.dataframe.station.values
def foo(name):
tf = mc.get_tf(name)
tf.plot_mt_response()
Q = interact(foo, name=widgets.Select(options=station_names, value='YNP05S'))
Loading...
name = Q.widget.kwargs['name']
tf = mc.get_tf(name)
fig, ax = plt.subplots(1,1, figsize=(5,5))
mc.dataframe.plot(x='longitude', y='latitude', marker='.', linestyle='None', ax=ax)
ax.plot(tf.longitude, tf.latitude, 'ro')
ax.set_title(name)
24:10:30T12:14:58 | WARNING | line:311 |mtpy.core.mt_collection | get_tf | Found multiple transfer functions with ID YNP05S. Suggest setting survey, otherwise returning the TF from survey YSBB.

frequencies = 1./tf.period
n_layer = 5
wire_map = maps.Wires(("sigma", n_layer), ("t", n_layer - 1))
sigma_map = maps.ExpMap(nP=n_layer) * wire_map.sigma
layer_map = maps.ExpMap(nP=n_layer - 1) * wire_map.t
model_mapping = maps.IdentityMap(nP=n_layer)
receivers_list = [
nsem.receivers.PointNaturalSource(component="app_res"),
nsem.receivers.PointNaturalSource(component="phase"),
]
source_list = []
for freq in frequencies:
source_list.append(nsem.sources.Planewave(receivers_list, freq))
survey = nsem.survey.Survey(source_list)
simulation = nsem.simulation_1d.Simulation1DRecursive(
survey=survey,
sigmaMap=sigma_map,
thicknessesMap=layer_map,
)
matplotlib.rcParams['font.size'] = 14
fig, axs = plt.subplots(2,1)
ax1, ax2 = axs
ax1.hist(tf.Z.res_error_det/tf.Z.res_det)
ax2.hist(tf.Z.phase_error_det)
(array([9., 7., 4., 2., 6., 1., 3., 3., 1., 1.]),
array([ 0.8955922 , 1.89325087, 2.89090955, 3.88856822, 4.88622689,
5.88388557, 6.88154424, 7.87920292, 8.87686159, 9.87452026,
10.87217894]),
<BarContainer object of 10 artists>)

app_rho = tf.Z.res_det.copy()
phase = tf.Z.phase_det.copy()
std = np.c_[abs(app_rho)*0.03, np.ones(len(phase))*2].flatten()
noise = np.c_[np.random.randn(app_rho.size)*0.03*abs(app_rho), np.random.randn(app_rho.size)*2].flatten()
dobs = np.c_[app_rho, phase].flatten()
data_object = data.Data(survey, dobs=dobs, standard_deviation=std)
starting_model = np.log(np.r_[np.ones(n_layer)*1./100, np.ones(n_layer-1)*1000])
# Define the data misfit. Here the data misfit is the L2 norm of the weighted
# residual between the observed data and the data predicted for a given model.
# Within the data misfit, the residual between predicted and observed data are
# normalized by the data's standard deviation.
dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_object)
mesh = TensorMesh([n_layer])
# Define the regularization on the parameters related to resistivity
mesh_sigma = TensorMesh([mesh.h[0].size])
reg_sigma = regularization.WeightedLeastSquares(mesh_sigma, alpha_s=0.01, alpha_x=0, mapping=wire_map.sigma)
# Define the regularization on the parameters related to layer thickness
mesh_t = TensorMesh([mesh.h[0].size - 1])
reg_t = regularization.WeightedLeastSquares(mesh_t, alpha_s=0.01, alpha_x=0, mapping=wire_map.t)
# Combine to make regularization for the inversion problem
reg = reg_sigma + reg_t
# Define how the optimization problem is solved. Here we will use an inexact
# Gauss-Newton approach that employs the conjugate gradient solver.
opt = optimization.InexactGaussNewton(maxIter=30, maxIterCG=50, maxIterLS=50)
# Define the inverse problem
inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)
#######################################################################
# Define Inversion Directives
# ---------------------------
#
# Here we define any directives that are carried out during the inversion. This
# includes the cooling schedule for the trade-off parameter (beta), stopping
# criteria for the inversion and saving inversion results at each iteration.
#
# Apply and update sensitivity weighting as the model updates
update_sensitivity_weights = directives.UpdateSensitivityWeights()
# Defining a starting value for the trade-off parameter (beta) between the data
# misfit and the regularization.
starting_beta = directives.BetaEstimate_ByEig(beta0_ratio=1e2)
# Set the rate of reduction in trade-off parameter (beta) each time the
# the inverse problem is solved. And set the number of Gauss-Newton iterations
# for each trade-off paramter value.
beta_schedule = directives.BetaSchedule(coolingFactor=5.0, coolingRate=3)
# Options for outputting recovered models and predicted data for each beta.
save_iteration = directives.SaveOutputEveryIteration(save_txt=False)
precond = directives.UpdatePreconditioner()
# Setting a stopping criteria for the inversion.
target_misfit = directives.TargetMisfit(chifact=1)
# The directives are defined in a list
directives_list = [
update_sensitivity_weights,
precond,
starting_beta,
beta_schedule,
target_misfit,
]
#####################################################################
# Running the Inversion
# ---------------------
#
# To define the inversion object, we need to define the inversion problem and
# the set of directives. We can then run the inversion.
#
# Here we combine the inverse problem and the set of directives
inv = inversion.BaseInversion(inv_prob, directiveList=directives_list)
# Run the inversion
recovered_model = inv.run(starting_model)
Running inversion with SimPEG v0.22.2
simpeg.InvProblem will set Regularization.reference_model to m0.
simpeg.InvProblem will set Regularization.reference_model to m0.
simpeg.InvProblem is setting bfgsH0 to the inverse of the eval2Deriv.
***Done using same Solver, and solver_opts as the Simulation1DRecursive problem***
model has any nan: 0
============================ Inexact Gauss Newton ============================
# beta phi_d phi_m f |proj(x-g)-x| LS Comment
-----------------------------------------------------------------------------
x0 has any nan: 0
0 2.88e+09 3.46e+04 0.00e+00 3.46e+04 7.44e+04 0
1 2.88e+09 1.37e+04 1.96e-06 1.93e+04 3.75e+04 0
2 2.88e+09 1.25e+04 4.91e-07 1.39e+04 1.86e+04 1
3 5.76e+08 1.22e+04 1.25e-07 1.23e+04 7.58e+03 1 Skip BFGS
4 5.76e+08 1.21e+04 6.69e-08 1.21e+04 3.72e+03 1 Skip BFGS
5 5.76e+08 1.21e+04 9.65e-08 1.21e+04 1.53e+03 0
6 1.15e+08 1.20e+04 9.74e-08 1.20e+04 6.44e+03 0
7 1.15e+08 1.19e+04 6.30e-07 1.19e+04 3.30e+03 1
8 1.15e+08 1.18e+04 1.08e-06 1.19e+04 1.67e+03 1 Skip BFGS
9 2.30e+07 1.17e+04 1.67e-06 1.17e+04 5.35e+03 0 Skip BFGS
10 2.30e+07 1.14e+04 6.07e-06 1.15e+04 2.72e+03 1
11 2.30e+07 1.11e+04 1.37e-05 1.15e+04 5.01e+02 0 Skip BFGS
12 4.61e+06 1.10e+04 1.42e-05 1.11e+04 3.50e+03 1 Skip BFGS
13 4.61e+06 1.03e+04 1.26e-04 1.09e+04 4.13e+03 0
14 4.61e+06 8.53e+03 2.00e-04 9.45e+03 2.82e+03 0
15 9.21e+05 7.56e+03 2.98e-04 7.83e+03 4.08e+03 1
16 9.21e+05 5.64e+03 6.58e-04 6.25e+03 3.44e+03 1
17 9.21e+05 4.16e+03 1.11e-03 5.18e+03 2.65e+03 0
18 1.84e+05 3.02e+03 1.53e-03 3.30e+03 3.65e+03 0
19 1.84e+05 1.55e+03 2.74e-03 2.05e+03 3.72e+03 1
20 1.84e+05 1.71e+02 3.55e-03 8.25e+02 1.34e+03 0 Skip BFGS
21 3.69e+04 1.84e+02 3.29e-03 3.06e+02 8.24e+02 0
22 3.69e+04 9.17e+01 3.86e-03 2.34e+02 8.34e+01 0
23 3.69e+04 9.04e+01 3.87e-03 2.33e+02 1.13e+01 0
24 7.37e+03 9.04e+01 3.87e-03 1.19e+02 1.37e+02 0
25 7.37e+03 8.61e+01 4.08e-03 1.16e+02 3.15e+01 0
26 7.37e+03 8.60e+01 4.09e-03 1.16e+02 2.07e+00 0
27 1.47e+03 8.60e+01 4.09e-03 9.21e+01 2.87e+01 0
28 1.47e+03 8.58e+01 4.15e-03 9.19e+01 4.12e+00 0
29 1.47e+03 8.58e+01 4.15e-03 9.19e+01 5.76e-01 0
30 2.95e+02 8.58e+01 4.15e-03 8.70e+01 5.79e+00 0
------------------------- STOP! -------------------------
1 : |fc-fOld| = 4.8965e+00 <= tolF*(1+|f0|) = 3.4617e+03
1 : |xc-x_last| = 1.1153e-03 <= tolX*(1+|x0|) = 1.8231e+00
0 : |proj(x-g)-x| = 5.7905e+00 <= tolG = 1.0000e-01
0 : |proj(x-g)-x| = 5.7905e+00 <= 1e3*eps = 1.0000e-02
1 : maxIter = 30 <= iter = 30
------------------------- DONE! -------------------------
import matplotlib.gridspec as gridspec
matplotlib.rcParams['font.size'] = 10
fig = plt.figure(figsize=(16*0.5, 5*0.5))
gs = gridspec.GridSpec(1, 5, figure=fig)
ax0 = fig.add_subplot(gs[0, 0])
x_min = 1
x_max = 1000
plot_1d_layer_model(
(layer_map * recovered_model)[::-1],
(1./(sigma_map * recovered_model))[::-1],
ax=ax0,
color="k"
)
ax0.set_xlabel("Resistivity ($\Omega$m)")
ax0.set_xlim(1, 1e4)
ax = fig.add_subplot(gs[0, 2:])
ax.loglog(1./frequencies, dobs.reshape((len(frequencies), 2))[:,0], 'x', color='C0', label='Obs.-Amp.')
ax.loglog(1./frequencies, inv_prob.dpred.reshape((len(frequencies), 2))[:,0], color='C0', label='Pred.-Amp.')
ax_1 = ax.twinx()
ax_1.plot(1./frequencies, dobs.reshape((len(frequencies), 2))[:,1], 'x', color='C1', label='Obs.-Pha.')
ax_1.plot(1./frequencies, inv_prob.dpred.reshape((len(frequencies), 2))[:,1], color='C1', label='Pred.-Pha.')
ax.set_xlabel("Period (s)")
ax.grid(True, which='both', alpha=0.5)
ax.set_ylabel("Apparent resistivity ($\Omega$m)")
ax_1.set_ylabel("Phase ($\degree$)")
ax.legend(bbox_to_anchor=(1.1,1))
ax.legend(loc=3)
ax_1.legend(loc=4)
ax.set_ylim(1, 10000)
ax_1.set_ylim(0, 90)
ax0.set_xlim(1, 10000)
plt.show()
