Skip to article frontmatterSkip to article content

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.
<Figure size 500x500 with 1 Axes>
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>)
<Figure size 640x480 with 2 Axes>
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()
<Figure size 800x250 with 3 Axes>