def fit_colecole_with_se(self, eta_cc=0.8, tau_cc=0.003, c_cc=0.6):
        def ColeColeSeigel(f, sigmaInf, eta, tau, c):
            w = 2 * np.pi * f
            return sigmaInf * (1 - eta / (1 + (1j * w * tau)**c))

        # Step1: Fit Cole-Cole with Stretched Exponential function
        time = np.logspace(-6, np.log10(0.01), 41)
        wt, tbase, omega_int = DigFilter.setFrequency(time)
        frequency = omega_int / (2 * np.pi)
        # Cole-Cole parameters
        siginf = 1.
        self.eta_cc = eta_cc
        self.tau_cc = tau_cc
        self.c_cc = c_cc

        sigma = ColeColeSeigel(frequency, siginf, eta_cc, tau_cc, c_cc)
        sigTCole = DigFilter.transFiltImpulse(sigma,
                                              wt,
                                              tbase,
                                              omega_int,
                                              time,
                                              tol=1e-12)
        wires = Maps.Wires(('eta', 1), ('tau', 1), ('c', 1))
        taumap = Maps.ExpMap(nP=1) * wires.tau
        survey = SESurvey()
        dtrue = -sigTCole
        survey.dobs = dtrue
        m1D = Mesh.TensorMesh([np.ones(3)])
        prob = SEInvImpulseProblem(m1D,
                                   etaMap=wires.eta,
                                   tauMap=taumap,
                                   cMap=wires.c)
        update_sens = Directives.UpdateSensitivityWeights()
        prob.time = time
        prob.pair(survey)
        m0 = np.r_[eta_cc, np.log(tau_cc), c_cc]
        perc = 0.05
        dmisfitpeta = DataMisfit.l2_DataMisfit(survey)
        dmisfitpeta.W = 1 / (abs(survey.dobs) * perc)
        reg = regularization.Simple(m1D)
        opt = Optimization.ProjectedGNCG(maxIter=10)
        invProb = InvProblem.BaseInvProblem(dmisfitpeta, reg, opt)
        # Create an inversion object
        target = Directives.TargetMisfit()
        invProb.beta = 0.
        inv = Inversion.BaseInversion(invProb, directiveList=[target])
        reg.mref = 0. * m0
        prob.counter = opt.counter = Utils.Counter()
        opt.LSshorten = 0.5
        opt.remember('xc')
        opt.tolX = 1e-20
        opt.tolF = 1e-20
        opt.tolG = 1e-20
        opt.eps = 1e-20
        mopt = inv.run(m0)
        return mopt
    def solve(self):
        # Tikhonov Inversion
        ####################

        # Initial model values
        m0 = np.median(self.ln_sigback) * np.ones(self.mapping.nP)
        m0 += np.random.randn(m0.size)

        # Misfit functional
        dmis = DataMisfit.l2_DataMisfit(self.survey.simpeg_survey)
        # Regularization functional
        regT = Regularization.Simple(self.mesh,
                                     alpha_s=10.0,
                                     alpha_x=10.0,
                                     alpha_y=10.0,
                                     alpha_z=10.0,
                                     indActive=self.actind)

        # Personal preference for this solver with a Jacobi preconditioner
        opt = Optimization.ProjectedGNCG(maxIter=8, tolX=1, maxIterCG=30)
        #opt = Optimization.ProjectedGradient(maxIter=100, tolX=1e-2,
        #                                 maxIterLS=20, maxIterCG=30, tolCG=1e-4)

        opt.printers.append(Optimization.IterationPrinters.iterationLS)
        #print(opt.printersLS)

        # Optimization class keeps value of 'xc'. Seems to be solution for the model parameters
        opt.remember('xc')
        invProb = InvProblem.BaseInvProblem(dmis, regT, opt)

        # Options for the inversion algorithm in particular selection of Beta weight for regularization.

        # How to choose initial estimate for beta
        beta = Directives.BetaEstimate_ByEig(beta0_ratio=1.)
        Target = Directives.TargetMisfit()
        # Beta changing algorithm.
        betaSched = Directives.BetaSchedule(coolingFactor=5., coolingRate=2)
        # Change model weights, seems sensitivity of conductivity ?? Not sure.
        updateSensW = Directives.UpdateSensitivityWeights(threshold=1e-3)
        # Use Jacobi preconditioner ( the only available).
        update_Jacobi = Directives.UpdatePreconditioner()

        inv = Inversion.BaseInversion(invProb,
                                      directiveList=[
                                          beta, Target, betaSched, updateSensW,
                                          update_Jacobi
                                      ])

        self.minv = inv.run(m0)
Пример #3
0
invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=beta * 10.)

# Here is where the norms are applied
IRLS = Directives.Update_IRLS(f_min_change=1e-4,
                              maxIRLSiter=20,
                              minGNiter=1,
                              beta_tol=0.5,
                              coolingRate=1,
                              coolEps_q=True,
                              betaSearch=False)

# Special directive specific to the mag amplitude problem. The sensitivity
# weights are update between each iteration.
ProjSpherical = Directives.ProjectSphericalBounds()
update_SensWeight = Directives.UpdateSensitivityWeights()
update_Jacobi = Directives.UpdatePreconditioner()

inv = Inversion.BaseInversion(
    invProb,
    directiveList=[ProjSpherical, IRLS, update_SensWeight, update_Jacobi])

mrec_MVI_S = inv.run(mstart)

#############################################################
# Final Plot
# ----------
#
# Let's compare the smooth and compact model
#
#
# Personal preference for this solver with a Jacobi preconditioner
opt = Optimization.ProjectedGNCG(maxIter=20,
                                 lower=-10,
                                 upper=10,
                                 maxIterLS=20,
                                 maxIterCG=30,
                                 tolCG=1e-4)

opt.remember('xc')
invProb = InvProblem.BaseInvProblem(dmis, regT, opt)

beta = Directives.BetaEstimate_ByEig(beta0_ratio=1.)
Target = Directives.TargetMisfit()
betaSched = Directives.BetaSchedule(coolingFactor=5., coolingRate=2)
updateSensW = Directives.UpdateSensitivityWeights(threshold=1e-3)
update_Jacobi = Directives.UpdatePreconditioner()

inv = Inversion.BaseInversion(
    invProb,
    directiveList=[beta, Target, betaSched, updateSensW, update_Jacobi])

minv = inv.run(m0)

# Final Plot
############

fig, ax = plt.subplots(1, 2, figsize=(12, 5))
ax = Utils.mkvc(ax)

cyl0v = getCylinderPoints(x0, z0, r0)
Пример #5
0
    def setUp(self):
        np.random.seed(0)
        H0 = (50000., 90., 0.)

        # The magnetization is set along a different
        # direction (induced + remanence)
        M = np.array([45., 90.])

        # Create grid of points for topography
        # Lets create a simple Gaussian topo
        # and set the active cells
        [xx, yy] = np.meshgrid(
            np.linspace(-200, 200, 50),
            np.linspace(-200, 200, 50)
        )
        b = 100
        A = 50
        zz = A*np.exp(-0.5*((xx/b)**2. + (yy/b)**2.))

        # We would usually load a topofile
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]

        # Create and array of observation points
        xr = np.linspace(-100., 100., 20)
        yr = np.linspace(-100., 100., 20)
        X, Y = np.meshgrid(xr, yr)
        Z = A*np.exp(-0.5*((X/b)**2. + (Y/b)**2.)) + 5

        # Create a MAGsurvey
        xyzLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        rxLoc = PF.BaseMag.RxObs(xyzLoc)
        srcField = PF.BaseMag.SrcField([rxLoc], param=H0)
        survey = PF.BaseMag.LinearSurvey(srcField)

        # Create a mesh
        h = [5, 5, 5]
        padDist = np.ones((3, 2)) * 100
        nCpad = [2, 4, 2]

        # Get extent of points
        limx = np.r_[topo[:, 0].max(), topo[:, 0].min()]
        limy = np.r_[topo[:, 1].max(), topo[:, 1].min()]
        limz = np.r_[topo[:, 2].max(), topo[:, 2].min()]

        # Get center of the mesh
        midX = np.mean(limx)
        midY = np.mean(limy)
        midZ = np.mean(limz)

        nCx = int(limx[0]-limx[1]) / h[0]
        nCy = int(limy[0]-limy[1]) / h[1]
        nCz = int(limz[0]-limz[1]+int(np.min(np.r_[nCx, nCy])/3)) / h[2]
        # Figure out full extent required from input
        extent = np.max(np.r_[nCx * h[0] + padDist[0, :].sum(),
                              nCy * h[1] + padDist[1, :].sum(),
                              nCz * h[2] + padDist[2, :].sum()])

        maxLevel = int(np.log2(extent/h[0]))+1

        # Number of cells at the small octree level
        nCx, nCy, nCz = 2**(maxLevel), 2**(maxLevel), 2**(maxLevel)

        # Define the mesh and origin
        # For now cubic cells
        mesh = Mesh.TreeMesh([np.ones(nCx)*h[0],
                              np.ones(nCx)*h[1],
                              np.ones(nCx)*h[2]])

        # Set origin
        mesh.x0 = np.r_[
            -nCx*h[0]/2.+midX,
            -nCy*h[1]/2.+midY,
            -nCz*h[2]/2.+midZ
        ]

        # Refine the mesh around topography
        # Get extent of points
        F = NearestNDInterpolator(topo[:, :2], topo[:, 2])
        zOffset = 0
        # Cycle through the first 3 octree levels
        for ii in range(3):

            dx = mesh.hx.min()*2**ii

            nCx = int((limx[0]-limx[1]) / dx)
            nCy = int((limy[0]-limy[1]) / dx)

            # Create a grid at the octree level in xy
            CCx, CCy = np.meshgrid(
                np.linspace(limx[1], limx[0], nCx),
                np.linspace(limy[1], limy[0], nCy)
            )

            z = F(mkvc(CCx), mkvc(CCy))

            # level means number of layers in current OcTree level
            for level in range(int(nCpad[ii])):

                mesh.insert_cells(
                    np.c_[
                        mkvc(CCx),
                        mkvc(CCy),
                        z-zOffset
                    ], np.ones_like(z)*maxLevel-ii,
                    finalize=False
                )

                zOffset += dx

        mesh.finalize()
        self.mesh = mesh
        # Define an active cells from topo
        actv = Utils.surface2ind_topo(mesh, topo)
        nC = int(actv.sum())

        model = np.zeros((mesh.nC, 3))

        # Convert the inclination declination to vector in Cartesian
        M_xyz = Utils.matutils.dip_azimuth2cartesian(M[0], M[1])

        # Get the indicies of the magnetized block
        ind = Utils.ModelBuilder.getIndicesBlock(
            np.r_[-20, -20, -10], np.r_[20, 20, 25],
            mesh.gridCC,
        )[0]

        # Assign magnetization values
        model[ind, :] = np.kron(
            np.ones((ind.shape[0], 1)), M_xyz*0.05
        )

        # Remove air cells
        self.model = model[actv, :]

        # Create active map to go from reduce set to full
        self.actvMap = Maps.InjectActiveCells(mesh, actv, np.nan)

        # Creat reduced identity map
        idenMap = Maps.IdentityMap(nP=nC*3)

        # Create the forward model operator
        prob = PF.Magnetics.MagneticIntegral(
            mesh, chiMap=idenMap, actInd=actv,
            modelType='vector'
        )

        # Pair the survey and problem
        survey.pair(prob)

        # Compute some data and add some random noise
        data = prob.fields(Utils.mkvc(self.model))
        std = 5  # nT
        data += np.random.randn(len(data))*std
        wd = np.ones(len(data))*std

        # Assigne data and uncertainties to the survey
        survey.dobs = data
        survey.std = wd

        # Create an projection matrix for plotting later
        actvPlot = Maps.InjectActiveCells(mesh, actv, np.nan)

        # Create sensitivity weights from our linear forward operator
        rxLoc = survey.srcField.rxList[0].locs

        # This Mapping connects the regularizations for the three-component
        # vector model
        wires = Maps.Wires(('p', nC), ('s', nC), ('t', nC))

        # Create sensitivity weights from our linear forward operator
        # so that all cells get equal chance to contribute to the solution
        wr = np.sum(prob.G**2., axis=0)**0.5
        wr = (wr/np.max(wr))

        # Create three regularization for the different components
        # of magnetization
        reg_p = Regularization.Sparse(mesh, indActive=actv, mapping=wires.p)
        reg_p.mref = np.zeros(3*nC)
        reg_p.cell_weights = (wires.p * wr)

        reg_s = Regularization.Sparse(mesh, indActive=actv, mapping=wires.s)
        reg_s.mref = np.zeros(3*nC)
        reg_s.cell_weights = (wires.s * wr)

        reg_t = Regularization.Sparse(mesh, indActive=actv, mapping=wires.t)
        reg_t.mref = np.zeros(3*nC)
        reg_t.cell_weights = (wires.t * wr)

        reg = reg_p + reg_s + reg_t
        reg.mref = np.zeros(3*nC)

        # Data misfit function
        dmis = DataMisfit.l2_DataMisfit(survey)
        dmis.W = 1./survey.std

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=30, lower=-10, upper=10.,
                                         maxIterLS=20, maxIterCG=20, tolCG=1e-4)

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)

        # A list of directive to control the inverson
        betaest = Directives.BetaEstimate_ByEig()

        # Here is where the norms are applied
        # Use pick a treshold parameter empirically based on the distribution of
        #  model parameters
        IRLS = Directives.Update_IRLS(
            f_min_change=1e-3, maxIRLSiter=0, beta_tol=5e-1
        )

        # Pre-conditioner
        update_Jacobi = Directives.UpdatePreconditioner()

        inv = Inversion.BaseInversion(invProb,
                                      directiveList=[IRLS, update_Jacobi, betaest])

        # Run the inversion
        m0 = np.ones(3*nC) * 1e-4  # Starting model
        mrec_MVIC = inv.run(m0)

        self.mstart = Utils.matutils.cartesian2spherical(mrec_MVIC.reshape((nC, 3), order='F'))
        beta = invProb.beta
        dmis.prob.coordinate_system = 'spherical'
        dmis.prob.model = self.mstart

        # Create a block diagonal regularization
        wires = Maps.Wires(('amp', nC), ('theta', nC), ('phi', nC))

        # Create a Combo Regularization
        # Regularize the amplitude of the vectors
        reg_a = Regularization.Sparse(mesh, indActive=actv,
                                      mapping=wires.amp)
        reg_a.norms = np.c_[0., 0., 0., 0.]  # Sparse on the model and its gradients
        reg_a.mref = np.zeros(3*nC)

        # Regularize the vertical angle of the vectors
        reg_t = Regularization.Sparse(mesh, indActive=actv,
                                      mapping=wires.theta)
        reg_t.alpha_s = 0.  # No reference angle
        reg_t.space = 'spherical'
        reg_t.norms = np.c_[2., 0., 0., 0.]  # Only norm on gradients used

        # Regularize the horizontal angle of the vectors
        reg_p = Regularization.Sparse(mesh, indActive=actv,
                                      mapping=wires.phi)
        reg_p.alpha_s = 0.  # No reference angle
        reg_p.space = 'spherical'
        reg_p.norms = np.c_[2., 0., 0., 0.]  # Only norm on gradients used

        reg = reg_a + reg_t + reg_p
        reg.mref = np.zeros(3*nC)

        Lbound = np.kron(np.asarray([0, -np.inf, -np.inf]), np.ones(nC))
        Ubound = np.kron(np.asarray([10, np.inf, np.inf]), np.ones(nC))

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=20,
                                         lower=Lbound,
                                         upper=Ubound,
                                         maxIterLS=20,
                                         maxIterCG=30,
                                         tolCG=1e-3,
                                         stepOffBoundsFact=1e-3,
                                         )
        opt.approxHinv = None

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=beta*10.)

        # Here is where the norms are applied
        IRLS = Directives.Update_IRLS(f_min_change=1e-4, maxIRLSiter=20,
                                      minGNiter=1, beta_tol=0.5,
                                      coolingRate=1, coolEps_q=True,
                                      betaSearch=False)

        # Special directive specific to the mag amplitude problem. The sensitivity
        # weights are update between each iteration.
        ProjSpherical = Directives.ProjectSphericalBounds()
        update_SensWeight = Directives.UpdateSensitivityWeights()
        update_Jacobi = Directives.UpdatePreconditioner()

        self.inv = Inversion.BaseInversion(
            invProb,
            directiveList=[
                ProjSpherical, IRLS, update_SensWeight, update_Jacobi
            ]
        )
def run(plotIt=True,
        survey_type="dipole-dipole",
        rho_background=1e3,
        rho_block=1e2,
        block_x0=100,
        block_dx=10,
        block_y0=-10,
        block_dy=5):

    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

    xmin, xmax = 0., 200.
    ymin, ymax = 0., 0.
    zmin, zmax = 0, 0
    endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]])
    # Generate DC survey object
    survey = DC.Utils.gen_DCIPsurvey(endl,
                                     survey_type=survey_type,
                                     dim=2,
                                     a=10,
                                     b=10,
                                     n=10)
    survey.getABMN_locations()
    survey = IO.from_ambn_locations_to_survey(survey.a_locations,
                                              survey.b_locations,
                                              survey.m_locations,
                                              survey.n_locations,
                                              survey_type,
                                              data_dc_type='volt')

    # Obtain 2D TensorMesh
    mesh, actind = IO.set_mesh()
    # Flat topography
    actind = Utils.surface2ind_topo(mesh, np.c_[mesh.vectorCCx,
                                                mesh.vectorCCx * 0.])
    survey.drapeTopo(mesh, actind, option="top")
    # Use Exponential Map: m = log(rho)
    actmap = Maps.InjectActiveCells(mesh,
                                    indActive=actind,
                                    valInactive=np.log(1e8))
    parametric_block = Maps.ParametricBlock(mesh, slopeFact=1e2)
    mapping = Maps.ExpMap(mesh) * parametric_block
    # Set true model
    # val_background,val_block, block_x0, block_dx, block_y0, block_dy
    mtrue = np.r_[np.log(1e3), np.log(10), 100, 10, -20, 10]

    # Set initial model
    m0 = np.r_[np.log(rho_background),
               np.log(rho_block), block_x0, block_dx, block_y0, block_dy]
    rho = mapping * mtrue
    rho0 = mapping * m0
    # Show the true conductivity model
    fig = plt.figure(figsize=(12, 3))
    ax = plt.subplot(111)
    temp = rho.copy()
    temp[~actind] = np.nan
    out = mesh.plotImage(temp,
                         grid=False,
                         ax=ax,
                         gridOpts={'alpha': 0.2},
                         clim=(10, 1000),
                         pcolorOpts={
                             "cmap": "viridis",
                             "norm": colors.LogNorm()
                         })
    ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1],
            'k.')
    ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
    ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
    cb = plt.colorbar(out[0])
    cb.set_label("Resistivity (ohm-m)")
    ax.set_aspect('equal')
    ax.set_title("True resistivity model")
    plt.show()
    # Show the true conductivity model
    fig = plt.figure(figsize=(12, 3))
    ax = plt.subplot(111)
    temp = rho0.copy()
    temp[~actind] = np.nan
    out = mesh.plotImage(temp,
                         grid=False,
                         ax=ax,
                         gridOpts={'alpha': 0.2},
                         clim=(10, 1000),
                         pcolorOpts={
                             "cmap": "viridis",
                             "norm": colors.LogNorm()
                         })
    ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1],
            'k.')
    ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
    ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
    cb = plt.colorbar(out[0])
    cb.set_label("Resistivity (ohm-m)")
    ax.set_aspect('equal')
    ax.set_title("Initial resistivity model")
    plt.show()

    # Generate 2.5D DC problem
    # "N" means potential is defined at nodes
    prb = DC.Problem2D_N(mesh, rhoMap=mapping, storeJ=True, Solver=Solver)
    # Pair problem with survey
    try:
        prb.pair(survey)
    except:
        survey.unpair()
        prb.pair(survey)

    # Make synthetic DC data with 5% Gaussian noise
    dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True)

    # Show apparent resisitivty pseudo-section
    IO.plotPseudoSection(data=survey.dobs / IO.G,
                         data_type='apparent_resistivity')

    # Show apparent resisitivty histogram
    fig = plt.figure()
    out = hist(survey.dobs / IO.G, bins=20)
    plt.show()
    # Set uncertainty
    # floor
    eps = 10**(-3.2)
    # percentage
    std = 0.05
    dmisfit = DataMisfit.l2_DataMisfit(survey)
    uncert = abs(survey.dobs) * std + eps
    dmisfit.W = 1. / uncert

    # Map for a regularization
    mesh_1d = Mesh.TensorMesh([parametric_block.nP])
    # Related to inversion
    reg = Regularization.Simple(mesh_1d, alpha_x=0.)
    opt = Optimization.InexactGaussNewton(maxIter=10)
    invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
    beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2)
    betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0)
    target = Directives.TargetMisfit()
    updateSensW = Directives.UpdateSensitivityWeights()
    update_Jacobi = Directives.UpdatePreconditioner()
    invProb.beta = 0.
    inv = Inversion.BaseInversion(invProb, directiveList=[target])
    prb.counter = opt.counter = Utils.Counter()
    opt.LSshorten = 0.5
    opt.remember('xc')

    # Run inversion
    mopt = inv.run(m0)

    # Convert obtained inversion model to resistivity
    # rho = M(m), where M(.) is a mapping

    rho_est = mapping * mopt
    rho_true = rho.copy()
    # show recovered conductivity
    vmin, vmax = rho.min(), rho.max()
    fig, ax = plt.subplots(2, 1, figsize=(20, 6))
    out1 = mesh.plotImage(rho_true,
                          clim=(10, 1000),
                          pcolorOpts={
                              "cmap": "viridis",
                              "norm": colors.LogNorm()
                          },
                          ax=ax[0])
    out2 = mesh.plotImage(rho_est,
                          clim=(10, 1000),
                          pcolorOpts={
                              "cmap": "viridis",
                              "norm": colors.LogNorm()
                          },
                          ax=ax[1])
    out = [out1, out2]
    for i in range(2):
        ax[i].plot(survey.electrode_locations[:, 0],
                   survey.electrode_locations[:, 1], 'kv')
        ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
        ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
        cb = plt.colorbar(out[i][0], ax=ax[i])
        cb.set_label("Resistivity ($\Omega$m)")
        ax[i].set_xlabel("Northing (m)")
        ax[i].set_ylabel("Elevation (m)")
        ax[i].set_aspect('equal')
    ax[0].set_title("True resistivity model")
    ax[1].set_title("Recovered resistivity model")
    plt.tight_layout()
    plt.show()
Пример #7
0
    def setUp(self):
        # We will assume a vertical inducing field
        H0 = (50000., 90., 0.)

        # The magnetization is set along a different direction (induced + remanence)
        M = np.array([90., 0.])

        # Block with an effective susceptibility
        chi_e = 0.05

        # Create grid of points for topography
        # Lets create a simple Gaussian topo and set the active cells
        [xx, yy] = np.meshgrid(np.linspace(-200, 200, 50),
                               np.linspace(-200, 200, 50))
        b = 100
        A = 50
        zz = A * np.exp(-0.5 * ((xx / b)**2. + (yy / b)**2.))
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]

        # Create and array of observation points
        xr = np.linspace(-100., 100., 20)
        yr = np.linspace(-100., 100., 20)
        X, Y = np.meshgrid(xr, yr)
        Z = A * np.exp(-0.5 * ((X / b)**2. + (Y / b)**2.)) + 5

        # Create a MAGsurvey
        rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        Rx = PF.BaseMag.RxObs(rxLoc)
        srcField = PF.BaseMag.SrcField([Rx], param=H0)
        survey = PF.BaseMag.LinearSurvey(srcField)

        # Create a mesh
        h = [5, 5, 5]
        padDist = np.ones((3, 2)) * 100
        nCpad = [4, 4, 2]

        # Get extent of points
        limx = np.r_[topo[:, 0].max(), topo[:, 0].min()]
        limy = np.r_[topo[:, 1].max(), topo[:, 1].min()]
        limz = np.r_[topo[:, 2].max(), topo[:, 2].min()]

        # Get center of the mesh
        midX = np.mean(limx)
        midY = np.mean(limy)
        midZ = np.mean(limz)

        nCx = int(limx[0] - limx[1]) / h[0]
        nCy = int(limy[0] - limy[1]) / h[1]
        nCz = int(limz[0] - limz[1] + int(np.min(np.r_[nCx, nCy]) / 3)) / h[2]

        # Figure out full extent required from input
        extent = np.max(np.r_[nCx * h[0] + padDist[0, :].sum(),
                              nCy * h[1] + padDist[1, :].sum(),
                              nCz * h[2] + padDist[2, :].sum()])

        maxLevel = int(np.log2(extent / h[0])) + 1

        # Number of cells at the small octree level
        # For now equal in 3D
        nCx, nCy, nCz = 2**(maxLevel), 2**(maxLevel), 2**(maxLevel)

        # Define the mesh and origin
        mesh = Mesh.TreeMesh(
            [np.ones(nCx) * h[0],
             np.ones(nCx) * h[1],
             np.ones(nCx) * h[2]])

        # Set origin
        mesh.x0 = np.r_[-nCx * h[0] / 2. + midX, -nCy * h[1] / 2. + midY,
                        -nCz * h[2] / 2. + midZ]

        # Refine the mesh around topography
        # Get extent of points
        F = NearestNDInterpolator(topo[:, :2], topo[:, 2])
        zOffset = 0
        # Cycle through the first 3 octree levels
        for ii in range(3):

            dx = mesh.hx.min() * 2**ii

            nCx = int((limx[0] - limx[1]) / dx)
            nCy = int((limy[0] - limy[1]) / dx)

            # Create a grid at the octree level in xy
            CCx, CCy = np.meshgrid(np.linspace(limx[1], limx[0], nCx),
                                   np.linspace(limy[1], limy[0], nCy))

            z = F(mkvc(CCx), mkvc(CCy))

            # level means number of layers in current OcTree level
            for level in range(int(nCpad[ii])):

                mesh.insert_cells(np.c_[mkvc(CCx),
                                        mkvc(CCy), z - zOffset],
                                  np.ones_like(z) * maxLevel - ii,
                                  finalize=False)

                zOffset += dx

        mesh.finalize()

        # Define an active cells from topo
        actv = Utils.surface2ind_topo(mesh, topo)
        nC = int(actv.sum())

        # Convert the inclination declination to vector in Cartesian
        M_xyz = Utils.matutils.dip_azimuth2cartesian(
            np.ones(nC) * M[0],
            np.ones(nC) * M[1])

        # Get the indicies of the magnetized block
        ind = Utils.ModelBuilder.getIndicesBlock(
            np.r_[-20, -20, -10],
            np.r_[20, 20, 25],
            mesh.gridCC,
        )[0]

        # Assign magnetization value, inducing field strength will
        # be applied in by the :class:`SimPEG.PF.Magnetics` problem
        model = np.zeros(mesh.nC)
        model[ind] = chi_e

        # Remove air cells
        self.model = model[actv]

        # Create active map to go from reduce set to full
        self.actvPlot = Maps.InjectActiveCells(mesh, actv, np.nan)

        # Creat reduced identity map
        idenMap = Maps.IdentityMap(nP=nC)

        # Create the forward model operator
        prob = PF.Magnetics.MagneticIntegral(mesh,
                                             M=M_xyz,
                                             chiMap=idenMap,
                                             actInd=actv)

        # Pair the survey and problem
        survey.pair(prob)

        # Compute some data and add some random noise
        data = prob.fields(self.model)

        # Split the data in components
        nD = rxLoc.shape[0]

        std = 5  # nT
        data += np.random.randn(nD) * std
        wd = np.ones(nD) * std

        # Assigne data and uncertainties to the survey
        survey.dobs = data
        survey.std = wd

        ######################################################################
        # Equivalent Source

        # Get the active cells for equivalent source is the top only
        surf = Utils.modelutils.surface_layer_index(mesh, topo)

        # Get the layer of cells directyl below topo
        nC = np.count_nonzero(surf)  # Number of active cells

        # Create active map to go from reduce set to full
        surfMap = Maps.InjectActiveCells(mesh, surf, np.nan)

        # Create identity map
        idenMap = Maps.IdentityMap(nP=nC)

        # Create static map
        prob = PF.Magnetics.MagneticIntegral(mesh,
                                             chiMap=idenMap,
                                             actInd=surf,
                                             parallelized=False,
                                             equiSourceLayer=True)

        prob.solverOpts['accuracyTol'] = 1e-4

        # Pair the survey and problem
        if survey.ispaired:
            survey.unpair()
        survey.pair(prob)

        # Create a regularization function, in this case l2l2
        reg = Regularization.Sparse(mesh,
                                    indActive=surf,
                                    mapping=Maps.IdentityMap(nP=nC),
                                    scaledIRLS=False)
        reg.mref = np.zeros(nC)

        # Specify how the optimization will proceed,
        # set susceptibility bounds to inf
        opt = Optimization.ProjectedGNCG(maxIter=20,
                                         lower=-np.inf,
                                         upper=np.inf,
                                         maxIterLS=20,
                                         maxIterCG=20,
                                         tolCG=1e-3)

        # Define misfit function (obs-calc)
        dmis = DataMisfit.l2_DataMisfit(survey)
        dmis.W = 1. / survey.std

        # Create the default L2 inverse problem from the above objects
        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)

        # Specify how the initial beta is found
        betaest = Directives.BetaEstimate_ByEig()

        # Target misfit to stop the inversion,
        # try to fit as much as possible of the signal,
        # we don't want to lose anything
        IRLS = Directives.Update_IRLS(f_min_change=1e-3,
                                      minGNiter=1,
                                      beta_tol=1e-1)
        update_Jacobi = Directives.UpdatePreconditioner()
        # Put all the parts together
        inv = Inversion.BaseInversion(
            invProb, directiveList=[betaest, IRLS, update_Jacobi])

        # Run the equivalent source inversion
        mstart = np.ones(nC) * 1e-4
        mrec = inv.run(mstart)

        # Won't store the sensitivity and output 'xyz' data.
        prob.forwardOnly = True
        prob.rx_type = 'xyz'
        prob._G = None
        prob.modelType = 'amplitude'
        prob.model = mrec
        pred = prob.fields(mrec)

        bx = pred[:nD]
        by = pred[nD:2 * nD]
        bz = pred[2 * nD:]

        bAmp = (bx**2. + by**2. + bz**2.)**0.5

        # AMPLITUDE INVERSION
        # Create active map to go from reduce space to full
        actvMap = Maps.InjectActiveCells(mesh, actv, -100)
        nC = int(actv.sum())

        # Create identity map
        idenMap = Maps.IdentityMap(nP=nC)

        self.mstart = np.ones(nC) * 1e-4

        # Create the forward model operator
        prob = PF.Magnetics.MagneticIntegral(mesh,
                                             chiMap=idenMap,
                                             actInd=actv,
                                             modelType='amplitude',
                                             rx_type='xyz')
        prob.model = self.mstart
        # Change the survey to xyz components
        surveyAmp = PF.BaseMag.LinearSurvey(survey.srcField)

        # Pair the survey and problem
        surveyAmp.pair(prob)
        # Create a regularization function, in this case l2l2
        wr = np.sum(prob.G**2., axis=0)**0.5
        wr = (wr / np.max(wr))
        # Re-set the observations to |B|
        surveyAmp.dobs = bAmp
        surveyAmp.std = wd

        # Create a sparse regularization
        reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
        reg.norms = np.c_[0, 0, 0, 0]
        reg.mref = np.zeros(nC)
        reg.cell_weights = wr
        # Data misfit function
        dmis = DataMisfit.l2_DataMisfit(surveyAmp)
        dmis.W = 1. / surveyAmp.std

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=30,
                                         lower=0.,
                                         upper=1.,
                                         maxIterLS=20,
                                         maxIterCG=20,
                                         tolCG=1e-3)

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)

        # Here is the list of directives
        betaest = Directives.BetaEstimate_ByEig()

        # Specify the sparse norms
        IRLS = Directives.Update_IRLS(f_min_change=1e-3,
                                      minGNiter=1,
                                      coolingRate=1,
                                      betaSearch=False)

        # The sensitivity weights are update between each iteration.
        update_SensWeight = Directives.UpdateSensitivityWeights()
        update_Jacobi = Directives.UpdatePreconditioner(threshold=1 - 3)

        # Put all together
        self.inv = Inversion.BaseInversion(
            invProb,
            directiveList=[betaest, IRLS, update_SensWeight, update_Jacobi])

        self.mesh = mesh
Пример #8
0
def run_inversion(
    m0, survey, actind, mesh,
    std, eps,
    maxIter=15, beta0_ratio=1e0,
    coolingFactor=5, coolingRate=2,
    upper=np.inf, lower=-np.inf,
    use_sensitivity_weight=False,
    alpha_s=1e-4,
    alpha_x=1.,
    alpha_y=1.,
    alpha_z=1.,
):
    """
    Run IP inversion
    """
    dmisfit = DataMisfit.l2_DataMisfit(survey)
    uncert = abs(survey.dobs) * std + eps
    dmisfit.W = 1./uncert
    # Map for a regularization
    regmap = Maps.IdentityMap(nP=int(actind.sum()))
    # Related to inversion
    if use_sensitivity_weight:
        reg = Regularization.Sparse(
            mesh, indActive=actind, mapping=regmap
        )
        reg.alpha_s = alpha_s
        reg.alpha_x = alpha_x
        reg.alpha_y = alpha_y
        reg.alpha_z = alpha_z
    else:
        reg = Regularization.Sparse(
            mesh, indActive=actind, mapping=regmap,
            cell_weights=mesh.vol[actind]
        )
        reg.alpha_s = alpha_s
        reg.alpha_x = alpha_x
        reg.alpha_y = alpha_y
        reg.alpha_z = alpha_z
    opt = Optimization.ProjectedGNCG(maxIter=maxIter, upper=upper, lower=lower)
    invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
    beta = Directives.BetaSchedule(
        coolingFactor=coolingFactor, coolingRate=coolingRate
    )
    betaest = Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio)
    target = Directives.TargetMisfit()

    # Need to have basice saving function
    if use_sensitivity_weight:
        updateSensW = Directives.UpdateSensitivityWeights()
        update_Jacobi = Directives.UpdatePreconditioner()
        directiveList = [
            beta, betaest, target, update_Jacobi
        ]
    else:
        directiveList = [
            beta, betaest, target
        ]
    inv = Inversion.BaseInversion(
        invProb, directiveList=directiveList
        )
    opt.LSshorten = 0.5
    opt.remember('xc')

    # Run inversion
    mopt = inv.run(m0)
    return mopt, invProb.dpred
def run(plotIt=True, survey_type="dipole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

    xmin, xmax = 0., 200.
    ymin, ymax = 0., 0.
    zmin, zmax = 0, 0
    endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]])
    # Generate DC survey object
    survey = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2,
                                     a=10, b=10, n=10)
    survey.getABMN_locations()
    survey = IO.from_ambn_locations_to_survey(
        survey.a_locations, survey.b_locations,
        survey.m_locations, survey.n_locations,
        survey_type, data_dc_type='volt'
    )

    # Obtain 2D TensorMesh
    mesh, actind = IO.set_mesh()
    topo, mesh1D = DC.Utils.genTopography(mesh, -10, 0, its=100)
    actind = Utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo])
    survey.drapeTopo(mesh, actind, option="top")

    # Build a conductivity model
    blk_inds_c = Utils.ModelBuilder.getIndicesSphere(
        np.r_[60., -25.], 12.5, mesh.gridCC
    )
    blk_inds_r = Utils.ModelBuilder.getIndicesSphere(
        np.r_[140., -25.], 12.5, mesh.gridCC
    )
    layer_inds = mesh.gridCC[:, 1] > -5.
    sigma = np.ones(mesh.nC)*1./100.
    sigma[blk_inds_c] = 1./10.
    sigma[blk_inds_r] = 1./1000.
    sigma[~actind] = 1./1e8
    rho = 1./sigma

    # Show the true conductivity model
    if plotIt:
        fig = plt.figure(figsize=(12, 3))
        ax = plt.subplot(111)
        temp = rho.copy()
        temp[~actind] = np.nan
        out = mesh.plotImage(
            temp, grid=True, ax=ax, gridOpts={'alpha': 0.2},
            clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()}
        )
        ax.plot(
            survey.electrode_locations[:, 0],
            survey.electrode_locations[:, 1], 'k.'
        )
        ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
        ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
        cb = plt.colorbar(out[0])
        cb.set_label("Resistivity (ohm-m)")
        ax.set_aspect('equal')
        plt.show()

    # Use Exponential Map: m = log(rho)
    actmap = Maps.InjectActiveCells(
        mesh, indActive=actind, valInactive=np.log(1e8)
    )
    mapping = Maps.ExpMap(mesh) * actmap

    # Generate mtrue
    mtrue = np.log(rho[actind])

    # Generate 2.5D DC problem
    # "N" means potential is defined at nodes
    prb = DC.Problem2D_N(
        mesh, rhoMap=mapping, storeJ=True,
        Solver=Solver
    )
    # Pair problem with survey
    try:
        prb.pair(survey)
    except:
        survey.unpair()
        prb.pair(survey)

    geometric_factor = survey.set_geometric_factor(
        data_type="apparent_resistivity",
        survey_type='dipole-dipole',
        space_type='half-space'
    )

    # Make synthetic DC data with 5% Gaussian noise
    dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True)

    IO.data_dc = dtrue
    # Show apparent resisitivty pseudo-section
    if plotIt:
        IO.plotPseudoSection(
            data=survey.dobs, data_type='apparent_resistivity'
        )

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure()
        out = hist(survey.dobs, bins=20)
        plt.xlabel("Apparent Resisitivty ($\Omega$m)")
        plt.show()

    # Set initial model based upon histogram
    m0 = np.ones(actmap.nP)*np.log(100.)

    # Set uncertainty
    # floor (10 ohm-m)
    eps = 1.
    # percentage
    std = 0.05
    dmisfit = DataMisfit.l2_DataMisfit(survey)
    uncert = abs(survey.dobs) * std + eps
    dmisfit.W = 1./uncert

    # Map for a regularization
    regmap = Maps.IdentityMap(nP=int(actind.sum()))

    # Related to inversion
    reg = Regularization.Sparse(mesh, indActive=actind, mapping=regmap)
    opt = Optimization.InexactGaussNewton(maxIter=15)
    invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
    beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2)
    betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0)
    target = Directives.TargetMisfit()
    updateSensW = Directives.UpdateSensitivityWeights()
    update_Jacobi = Directives.UpdatePreconditioner()
    inv = Inversion.BaseInversion(
        invProb, directiveList=[
            beta, betaest, target, updateSensW, update_Jacobi
        ]
        )
    prb.counter = opt.counter = Utils.Counter()
    opt.LSshorten = 0.5
    opt.remember('xc')

    # Run inversion
    mopt = inv.run(m0)

    # Get diag(JtJ)
    mask_inds = np.ones(mesh.nC, dtype=bool)
    jtj = np.sqrt(updateSensW.JtJdiag[0])
    jtj /= jtj.max()
    temp = np.ones_like(jtj, dtype=bool)
    temp[jtj > 0.005] = False
    mask_inds[actind] = temp
    actind_final = np.logical_and(actind, ~mask_inds)
    jtj_cc = np.ones(mesh.nC)*np.nan
    jtj_cc[actind] = jtj

    # Show the sensitivity
    if plotIt:
        fig = plt.figure(figsize=(12, 3))
        ax = plt.subplot(111)
        temp = rho.copy()
        temp[~actind] = np.nan
        out = mesh.plotImage(
            jtj_cc, grid=True, ax=ax,
            gridOpts={'alpha': 0.2}, clim=(0.005, 0.5),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()}
        )
        ax.plot(
            survey.electrode_locations[:, 0],
            survey.electrode_locations[:, 1], 'k.'
        )
        ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
        ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
        cb = plt.colorbar(out[0])
        cb.set_label("Sensitivity")
        ax.set_aspect('equal')
        plt.show()

    # Convert obtained inversion model to resistivity
    # rho = M(m), where M(.) is a mapping

    rho_est = mapping*mopt
    rho_est[~actind_final] = np.nan
    rho_true = rho.copy()
    rho_true[~actind_final] = np.nan

    # show recovered conductivity
    if plotIt:
        vmin, vmax = rho.min(), rho.max()
        fig, ax = plt.subplots(2, 1, figsize=(20, 6))
        out1 = mesh.plotImage(
                rho_true, clim=(10, 1000),
                pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
                ax=ax[0]
        )
        out2 = mesh.plotImage(
            rho_est, clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
            ax=ax[1]
        )
        out = [out1, out2]
        for i in range(2):
            ax[i].plot(
                survey.electrode_locations[:, 0],
                survey.electrode_locations[:, 1], 'kv'
            )
            ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
            ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
            cb = plt.colorbar(out[i][0], ax=ax[i])
            cb.set_label("Resistivity ($\Omega$m)")
            ax[i].set_xlabel("Northing (m)")
            ax[i].set_ylabel("Elevation (m)")
            ax[i].set_aspect('equal')
        plt.tight_layout()
        plt.show()
    def setUp(self):
        # We will assume a vertical inducing field
        H0 = (50000., 90., 0.)

        # The magnetization is set along a different direction (induced + remanence)
        M = np.array([90., 0.])

        # Block with an effective susceptibility
        chi_e = 0.05

        # Create grid of points for topography
        # Lets create a simple Gaussian topo and set the active cells
        [xx, yy] = np.meshgrid(np.linspace(-200, 200, 50),
                               np.linspace(-200, 200, 50))
        b = 100
        A = 50
        zz = A * np.exp(-0.5 * ((xx / b)**2. + (yy / b)**2.))
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]

        # Create and array of observation points
        xr = np.linspace(-100., 100., 20)
        yr = np.linspace(-100., 100., 20)
        X, Y = np.meshgrid(xr, yr)
        Z = A * np.exp(-0.5 * ((X / b)**2. + (Y / b)**2.)) + 5

        # Create a MAGsurvey
        xyzLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        Rx = PF.BaseMag.RxObs(xyzLoc)
        srcField = PF.BaseMag.SrcField([Rx], param=H0)
        survey = PF.BaseMag.LinearSurvey(srcField)

        # Create a mesh
        h = [5, 5, 5]
        padDist = np.ones((3, 2)) * 100
        nCpad = [4, 4, 2]

        self.mesh = meshutils.mesh_builder_xyz(
            xyzLoc,
            h,
            padding_distance=padDist,
            mesh_type='TREE',
        )

        self.mesh = meshutils.refine_tree_xyz(
            self.mesh,
            topo,
            method='surface',
            octree_levels=nCpad,
            octree_levels_padding=nCpad,
            finalize=True,
        )
        # Define an active cells from topo
        actv = Utils.surface2ind_topo(self.mesh, topo)
        nC = int(actv.sum())

        # Convert the inclination declination to vector in Cartesian
        M_xyz = Utils.matutils.dip_azimuth2cartesian(
            np.ones(nC) * M[0],
            np.ones(nC) * M[1])

        # Get the indicies of the magnetized block
        ind = Utils.ModelBuilder.getIndicesBlock(
            np.r_[-20, -20, -15],
            np.r_[20, 20, 20],
            self.mesh.gridCC,
        )[0]

        # Assign magnetization value, inducing field strength will
        # be applied in by the :class:`SimPEG.PF.Magnetics` problem
        model = np.zeros(self.mesh.nC)
        model[ind] = chi_e

        # Remove air cells
        self.model = model[actv]

        # Create active map to go from reduce set to full
        self.actvPlot = Maps.InjectActiveCells(self.mesh, actv, np.nan)

        # Creat reduced identity map
        idenMap = Maps.IdentityMap(nP=nC)

        # Create the forward model operator
        prob = PF.Magnetics.MagneticIntegral(self.mesh,
                                             M=M_xyz,
                                             chiMap=idenMap,
                                             actInd=actv)

        # Pair the survey and problem
        survey.pair(prob)

        # Compute some data and add some random noise
        data = prob.fields(self.model)

        # Split the data in components
        nD = xyzLoc.shape[0]

        std = 5  # nT
        data += np.random.randn(nD) * std
        wd = np.ones(nD) * std

        # Assigne data and uncertainties to the survey
        survey.dobs = data
        survey.std = wd

        ######################################################################
        # Equivalent Source

        # Get the active cells for equivalent source is the top only
        surf = Utils.modelutils.surface_layer_index(self.mesh, topo)

        # Get the layer of cells directyl below topo
        nC = np.count_nonzero(surf)  # Number of active cells

        # Create active map to go from reduce set to full
        surfMap = Maps.InjectActiveCells(self.mesh, surf, np.nan)

        # Create identity map
        idenMap = Maps.IdentityMap(nP=nC)

        # Create static map
        prob = PF.Magnetics.MagneticIntegral(self.mesh,
                                             chiMap=idenMap,
                                             actInd=surf,
                                             parallelized=False,
                                             equiSourceLayer=True)

        prob.solverOpts['accuracyTol'] = 1e-4

        # Pair the survey and problem
        if survey.ispaired:
            survey.unpair()
        survey.pair(prob)

        # Create a regularization function, in this case l2l2
        reg = Regularization.Sparse(self.mesh,
                                    indActive=surf,
                                    mapping=Maps.IdentityMap(nP=nC),
                                    scaledIRLS=False)
        reg.mref = np.zeros(nC)

        # Specify how the optimization will proceed,
        # set susceptibility bounds to inf
        opt = Optimization.ProjectedGNCG(maxIter=20,
                                         lower=-np.inf,
                                         upper=np.inf,
                                         maxIterLS=20,
                                         maxIterCG=20,
                                         tolCG=1e-3)

        # Define misfit function (obs-calc)
        dmis = DataMisfit.l2_DataMisfit(survey)
        dmis.W = 1. / survey.std

        # Create the default L2 inverse problem from the above objects
        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)

        # Specify how the initial beta is found
        betaest = Directives.BetaEstimate_ByEig()

        # Target misfit to stop the inversion,
        # try to fit as much as possible of the signal,
        # we don't want to lose anything
        IRLS = Directives.Update_IRLS(f_min_change=1e-3,
                                      minGNiter=1,
                                      beta_tol=1e-1)
        update_Jacobi = Directives.UpdatePreconditioner()
        # Put all the parts together
        inv = Inversion.BaseInversion(
            invProb, directiveList=[betaest, IRLS, update_Jacobi])

        # Run the equivalent source inversion
        mstart = np.ones(nC) * 1e-4
        mrec = inv.run(mstart)

        # Won't store the sensitivity and output 'xyz' data.
        prob.forwardOnly = True
        prob.rx_type = 'xyz'
        prob._G = None
        prob.modelType = 'amplitude'
        prob.model = mrec
        pred = prob.fields(mrec)

        bx = pred[:nD]
        by = pred[nD:2 * nD]
        bz = pred[2 * nD:]

        bAmp = (bx**2. + by**2. + bz**2.)**0.5

        # AMPLITUDE INVERSION
        # Create active map to go from reduce space to full
        actvMap = Maps.InjectActiveCells(self.mesh, actv, -100)
        nC = int(actv.sum())

        # Create identity map
        idenMap = Maps.IdentityMap(nP=nC)

        self.mstart = np.ones(nC) * 1e-4

        # Create the forward model operator
        prob = PF.Magnetics.MagneticIntegral(self.mesh,
                                             chiMap=idenMap,
                                             actInd=actv,
                                             modelType='amplitude',
                                             rx_type='xyz')
        prob.model = self.mstart
        # Change the survey to xyz components
        surveyAmp = PF.BaseMag.LinearSurvey(survey.srcField)

        # Pair the survey and problem
        surveyAmp.pair(prob)
        # Create a regularization function, in this case l2l2
        wr = np.sum(prob.G**2., axis=0)**0.5
        wr /= np.max(wr)
        # Re-set the observations to |B|
        surveyAmp.dobs = bAmp
        surveyAmp.std = wd

        # Create a sparse regularization
        reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap)
        reg.norms = np.c_[0, 0, 0, 0]
        reg.mref = np.zeros(nC)
        reg.cell_weights = wr
        # Data misfit function
        dmis = DataMisfit.l2_DataMisfit(surveyAmp)
        dmis.W = 1. / surveyAmp.std

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=30,
                                         lower=0.,
                                         upper=1.,
                                         maxIterLS=20,
                                         maxIterCG=20,
                                         tolCG=1e-3)

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)

        # Here is the list of directives
        betaest = Directives.BetaEstimate_ByEig()

        # Specify the sparse norms
        IRLS = Directives.Update_IRLS(f_min_change=1e-3,
                                      minGNiter=1,
                                      coolingRate=1,
                                      betaSearch=False)

        # The sensitivity weights are update between each iteration.
        update_SensWeight = Directives.UpdateSensitivityWeights()
        update_Jacobi = Directives.UpdatePreconditioner()

        # Put all together
        self.inv = Inversion.BaseInversion(
            invProb,
            directiveList=[betaest, IRLS, update_SensWeight, update_Jacobi])