.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "content/user-guide/tutorials/02-linear_inversion/plot_inv_2_inversion_irls.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_content_user-guide_tutorials_02-linear_inversion_plot_inv_2_inversion_irls.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_content_user-guide_tutorials_02-linear_inversion_plot_inv_2_inversion_irls.py:


Sparse Inversion with Iteratively Re-Weighted Least-Squares
===========================================================

Least-squares inversion produces smooth models which may not be an accurate
representation of the true model. Here we demonstrate the basics of inverting
for sparse and/or blocky models. Here, we used the iteratively reweighted
least-squares approach. For this tutorial, we focus on the following:

    - Defining the forward problem
    - Defining the inverse problem (data misfit, regularization, optimization)
    - Defining the paramters for the IRLS algorithm
    - Specifying directives for the inversion
    - Recovering a set of model parameters which explains the observations

.. GENERATED FROM PYTHON SOURCE LINES 18-37

.. code-block:: Python


    import numpy as np
    import matplotlib.pyplot as plt

    from discretize import TensorMesh

    from simpeg import (
        simulation,
        maps,
        data_misfit,
        directives,
        optimization,
        regularization,
        inverse_problem,
        inversion,
    )

    # sphinx_gallery_thumbnail_number = 3








.. GENERATED FROM PYTHON SOURCE LINES 38-44

Defining the Model and Mapping
------------------------------

Here we generate a synthetic model and a mappig which goes from the model
space to the row space of our linear operator.


.. GENERATED FROM PYTHON SOURCE LINES 44-65

.. code-block:: Python


    nParam = 100  # Number of model paramters

    # A 1D mesh is used to define the row-space of the linear operator.
    mesh = TensorMesh([nParam])

    # Creating the true model
    true_model = np.zeros(mesh.nC)
    true_model[mesh.cell_centers_x > 0.3] = 1.0
    true_model[mesh.cell_centers_x > 0.45] = -0.5
    true_model[mesh.cell_centers_x > 0.6] = 0

    # Mapping from the model space to the row space of the linear operator
    model_map = maps.IdentityMap(mesh)

    # Plotting the true model
    fig = plt.figure(figsize=(8, 5))
    ax = fig.add_subplot(111)
    ax.plot(mesh.cell_centers_x, true_model, "b-")
    ax.set_ylim([-2, 2])




.. image-sg:: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_001.png
   :alt: plot inv 2 inversion irls
   :srcset: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_001.png
   :class: sphx-glr-single-img


.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    (-2.0, 2.0)



.. GENERATED FROM PYTHON SOURCE LINES 66-73

Defining the Linear Operator
----------------------------

Here we define the linear operator with dimensions (nData, nParam). In practive,
you may have a problem-specific linear operator which you would like to construct
or load here.


.. GENERATED FROM PYTHON SOURCE LINES 73-104

.. code-block:: Python


    # Number of data observations (rows)
    nData = 20

    # Create the linear operator for the tutorial. The columns of the linear operator
    # represents a set of decaying and oscillating functions.
    jk = np.linspace(1.0, 60.0, nData)
    p = -0.25
    q = 0.25


    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((nData, nParam))

    for i in range(nData):
        G[i, :] = g(i)

    # Plot the columns of G
    fig = plt.figure(figsize=(8, 5))
    ax = fig.add_subplot(111)
    for i in range(G.shape[0]):
        ax.plot(G[i, :])

    ax.set_title("Columns of matrix G")





.. image-sg:: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_002.png
   :alt: Columns of matrix G
   :srcset: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_002.png
   :class: sphx-glr-single-img


.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    Text(0.5, 1.0, 'Columns of matrix G')



.. GENERATED FROM PYTHON SOURCE LINES 105-111

Defining the Simulation
-----------------------

The simulation defines the relationship between the model parameters and
predicted data.


.. GENERATED FROM PYTHON SOURCE LINES 111-115

.. code-block:: Python


    sim = simulation.LinearSimulation(mesh, G=G, model_map=model_map)









.. GENERATED FROM PYTHON SOURCE LINES 116-122

Predict Synthetic Data
----------------------

Here, we use the true model to create synthetic data which we will subsequently
invert.


.. GENERATED FROM PYTHON SOURCE LINES 122-130

.. code-block:: Python


    # Standard deviation of Gaussian noise being added
    std = 0.02
    np.random.seed(1)

    # Create a SimPEG data object
    data_obj = sim.make_synthetic_data(true_model, noise_floor=std, add_noise=True)








.. GENERATED FROM PYTHON SOURCE LINES 131-140

Define the Inverse Problem
--------------------------

The inverse problem is defined by 3 things:

    1) Data Misfit: a measure of how well our recovered model explains the field data
    2) Regularization: constraints placed on the recovered model and a priori information
    3) Optimization: the numerical approach used to solve the inverse problem


.. GENERATED FROM PYTHON SOURCE LINES 140-164

.. code-block:: Python


    # 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=sim, data=data_obj)

    # Define the regularization (model objective function). Here, 'p' defines the
    # the norm of the smallness term and 'q' defines the norm of the smoothness
    # term.
    reg = regularization.Sparse(mesh, mapping=model_map)
    reg.reference_model = np.zeros(nParam)
    p = 0.0
    q = 0.0
    reg.norms = [p, q]

    # Define how the optimization problem is solved.
    opt = optimization.ProjectedGNCG(
        maxIter=100, lower=-2.0, upper=2.0, maxIterLS=20, maxIterCG=30, tolCG=1e-4
    )

    # Here we define the inverse problem that is to be solved
    inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)








.. GENERATED FROM PYTHON SOURCE LINES 165-172

Define Inversion Directives
---------------------------

Here we define any directiveas 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.


.. GENERATED FROM PYTHON SOURCE LINES 172-199

.. code-block:: Python


    # Add sensitivity weights but don't update at each beta
    sensitivity_weights = directives.UpdateSensitivityWeights(every_iteration=False)

    # Reach target misfit for L2 solution, then use IRLS until model stops changing.
    IRLS = directives.UpdateIRLS(max_irls_iterations=40, f_min_change=1e-4)

    # Defining a starting value for the trade-off parameter (beta) between the data
    # misfit and the regularization.
    starting_beta = directives.BetaEstimate_ByEig(beta0_ratio=1e0)

    # Update the preconditionner
    update_Jacobi = directives.UpdatePreconditioner()

    # Save output at each iteration
    saveDict = directives.SaveOutputEveryIteration(save_txt=False)

    # Define the directives as a list
    directives_list = [
        sensitivity_weights,
        IRLS,
        starting_beta,
        update_Jacobi,
        saveDict,
    ]









.. GENERATED FROM PYTHON SOURCE LINES 200-206

Setting a Starting Model and 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.


.. GENERATED FROM PYTHON SOURCE LINES 206-216

.. code-block:: Python


    # Here we combine the inverse problem and the set of directives
    inv = inversion.BaseInversion(inv_prob, directives_list)

    # Starting model
    starting_model = 1e-4 * np.ones(nParam)

    # Run inversion
    recovered_model = inv.run(starting_model)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    Running inversion with SimPEG v0.23.1.dev27+g1148ef1e9

                        simpeg.InvProblem is setting bfgsH0 to the inverse of the eval2Deriv.
                        ***Done using the default solver Pardiso and no solver_opts.***
                    
    model has any nan: 0
    =============================== Projected GNCG ===============================
      #     beta     phi_d     phi_m       f      |proj(x-g)-x|  LS    Comment   
    -----------------------------------------------------------------------------
    x0 has any nan: 0
       0  1.68e+06  3.75e+03  1.02e-09  3.75e+03    1.99e+01      0              
       1  8.39e+05  1.94e+03  3.80e-04  2.26e+03    1.93e+01      0              
       2  4.20e+05  1.35e+03  8.89e-04  1.72e+03    1.88e+01      0   Skip BFGS  
       3  2.10e+05  8.02e+02  1.82e-03  1.18e+03    1.77e+01      0   Skip BFGS  
       4  1.05e+05  4.04e+02  3.15e-03  7.34e+02    1.66e+01      0   Skip BFGS  
       5  5.24e+04  1.75e+02  4.67e-03  4.19e+02    1.43e+01      0   Skip BFGS  
       6  2.62e+04  6.71e+01  6.08e-03  2.26e+02    1.29e+01      0   Skip BFGS  
       7  1.31e+04  2.48e+01  7.17e-03  1.19e+02    1.04e+01      0   Skip BFGS  
    Reached starting chifact with l2-norm regularization: Start IRLS steps...
    irls_threshold 1.2958778692678472
       8  1.31e+04  1.05e+01  1.09e-02  1.53e+02    1.47e+01      0   Skip BFGS  
       9  1.31e+04  1.81e+01  1.15e-02  1.69e+02    1.37e+01      0              
      10  8.11e+03  2.46e+01  1.21e-02  1.23e+02    8.80e+00      0   Skip BFGS  
      11  5.02e+03  1.93e+01  1.35e-02  8.70e+01    8.86e+00      0              
      12  6.77e+03  1.47e+01  1.44e-02  1.12e+02    1.58e+01      0   Skip BFGS  
      13  9.13e+03  2.12e+01  1.35e-02  1.45e+02    1.62e+01      0              
      14  5.06e+03  3.21e+01  1.21e-02  9.33e+01    1.39e+01      0              
      15  2.81e+03  2.17e+01  1.22e-02  5.59e+01    1.14e+01      0              
      16  4.05e+03  1.27e+01  1.22e-02  6.23e+01    1.38e+01      0              
      17  5.40e+03  1.50e+01  1.06e-02  7.23e+01    1.39e+01      0              
      18  7.21e+03  1.85e+01  9.04e-03  8.37e+01    1.42e+01      0              
      19  4.59e+03  2.28e+01  7.70e-03  5.82e+01    9.31e+00      0              
      20  5.59e+03  1.79e+01  6.99e-03  5.69e+01    1.17e+01      0              
      21  6.80e+03  1.82e+01  5.88e-03  5.82e+01    1.22e+01      0              
      22  8.27e+03  1.92e+01  4.88e-03  5.96e+01    1.28e+01      0              
      23  1.01e+04  2.02e+01  3.93e-03  5.97e+01    1.31e+01      0              
      24  1.23e+04  2.05e+01  3.12e-03  5.88e+01    1.30e+01      0              
      25  1.49e+04  2.02e+01  2.56e-03  5.83e+01    1.34e+01      0              
      26  1.81e+04  2.01e+01  2.22e-03  6.04e+01    1.43e+01      0              
      27  2.21e+04  2.09e+01  1.94e-03  6.38e+01    1.49e+01      0              
      28  1.42e+04  2.23e+01  1.70e-03  4.64e+01    1.18e+01      0              
      29  1.74e+04  1.76e+01  1.50e-03  4.38e+01    1.43e+01      0              
      30  2.23e+04  1.61e+01  1.19e-03  4.28e+01    1.43e+01      0              
      31  2.95e+04  1.53e+01  9.52e-04  4.34e+01    1.48e+01      0              
      32  3.92e+04  1.50e+01  7.43e-04  4.42e+01    1.51e+01      0              
      33  5.21e+04  1.52e+01  5.89e-04  4.58e+01    1.50e+01      0              
      34  6.82e+04  1.55e+01  4.77e-04  4.81e+01    1.50e+01      0   Skip BFGS  
      35  8.80e+04  1.60e+01  3.88e-04  5.01e+01    1.51e+01      0              
      36  1.12e+05  1.65e+01  3.17e-04  5.19e+01    1.50e+01      0              
      37  1.40e+05  1.69e+01  2.60e-04  5.34e+01    1.48e+01      0              
      38  1.73e+05  1.73e+01  2.16e-04  5.47e+01    1.45e+01      0              
      39  2.13e+05  1.76e+01  1.80e-04  5.58e+01    1.45e+01      0              
      40  2.60e+05  1.78e+01  1.50e-04  5.66e+01    1.45e+01      0              
      41  3.17e+05  1.77e+01  1.25e-04  5.73e+01    1.46e+01      0              
      42  3.90e+05  1.75e+01  1.00e-04  5.66e+01    1.46e+01      0              
      43  4.82e+05  1.74e+01  8.25e-05  5.72e+01    1.47e+01      0              
      44  5.95e+05  1.74e+01  6.88e-05  5.83e+01    1.46e+01      0   Skip BFGS  
      45  7.30e+05  1.76e+01  5.73e-05  5.94e+01    1.46e+01      0   Skip BFGS  
      46  8.91e+05  1.78e+01  4.76e-05  6.02e+01    1.44e+01      0              
      47  1.09e+06  1.80e+01  3.96e-05  6.10e+01    1.45e+01      0   Skip BFGS  
    Reach maximum number of IRLS cycles: 40
    ------------------------- STOP! -------------------------
    1 : |fc-fOld| = 0.0000e+00 <= tolF*(1+|f0|) = 3.7533e+02
    1 : |xc-x_last| = 1.4605e-02 <= tolX*(1+|x0|) = 1.0010e-01
    0 : |proj(x-g)-x|    = 1.4461e+01 <= tolG          = 1.0000e-01
    0 : |proj(x-g)-x|    = 1.4461e+01 <= 1e3*eps       = 1.0000e-02
    0 : maxIter   =     100    <= iter          =     48
    ------------------------- DONE! -------------------------




.. GENERATED FROM PYTHON SOURCE LINES 217-220

Plotting Results
----------------


.. GENERATED FROM PYTHON SOURCE LINES 220-261

.. code-block:: Python


    fig, ax = plt.subplots(1, 2, figsize=(12 * 1.2, 4 * 1.2))

    # True versus recovered model
    ax[0].plot(mesh.cell_centers_x, true_model, "k-")
    ax[0].plot(mesh.cell_centers_x, inv_prob.l2model, "b-")
    ax[0].plot(mesh.cell_centers_x, recovered_model, "r-")
    ax[0].legend(("True Model", "Recovered L2 Model", "Recovered Sparse Model"))
    ax[0].set_ylim([-2, 2])

    # Observed versus predicted data
    ax[1].plot(data_obj.dobs, "k-")
    ax[1].plot(inv_prob.dpred, "ko")
    ax[1].legend(("Observed Data", "Predicted Data"))

    # Plot convergence
    fig = plt.figure(figsize=(9, 5))
    ax = fig.add_axes([0.2, 0.1, 0.7, 0.85])
    ax.plot(saveDict.phi_d, "k", lw=2)

    twin = ax.twinx()
    twin.plot(saveDict.phi_m, "k--", lw=2)
    ax.plot(
        np.r_[IRLS.metrics.start_irls_iter, IRLS.metrics.start_irls_iter],
        np.r_[0, np.max(saveDict.phi_d)],
        "k:",
    )
    ax.text(
        IRLS.metrics.start_irls_iter,
        0.0,
        "IRLS Start",
        va="bottom",
        ha="center",
        rotation="vertical",
        size=12,
        bbox={"facecolor": "white"},
    )

    ax.set_ylabel(r"$\phi_d$", size=16, rotation=0)
    ax.set_xlabel("Iterations", size=14)
    twin.set_ylabel(r"$\phi_m$", size=16, rotation=0)



.. rst-class:: sphx-glr-horizontal


    *

      .. image-sg:: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_003.png
         :alt: plot inv 2 inversion irls
         :srcset: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_003.png
         :class: sphx-glr-multi-img

    *

      .. image-sg:: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_004.png
         :alt: plot inv 2 inversion irls
         :srcset: /content/user-guide/tutorials/02-linear_inversion/images/sphx_glr_plot_inv_2_inversion_irls_004.png
         :class: sphx-glr-multi-img


.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    Text(865.1527777777777, 0.5, '$\\phi_m$')




.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 38.663 seconds)

**Estimated memory usage:**  295 MB


.. _sphx_glr_download_content_user-guide_tutorials_02-linear_inversion_plot_inv_2_inversion_irls.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_inv_2_inversion_irls.ipynb <plot_inv_2_inversion_irls.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_inv_2_inversion_irls.py <plot_inv_2_inversion_irls.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_inv_2_inversion_irls.zip <plot_inv_2_inversion_irls.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_