Beispiel #1
0
    def profiledata(Binc, Bdec, Bigrf, depth, susc, comp, irt, Q, rinc, rdec,
                    update):

        # Get the line extent from the 2D survey for now
        sim = Mag.Simulation()
        sim.prism = prism.result

        xyzLoc = survey.receiver_locations.copy()
        xyzLoc[:, 2] += depth

        rxLoc = mag.receivers.Point(xyzLoc)
        srcField = mag.sources.SourceField(receiver_list=[rxLoc],
                                           parameters=(Bigrf, -Binc, Bdec))
        survey2D = mag.Survey(srcField)
        sim.survey = survey2D

        sim.Q, sim.rinc, sim.rdec = Q, -rinc, rdec
        sim.uType, sim.mType = comp, irt
        sim.susc = susc

        # Compute fields from prism
        fields = sim.fields()

        dpred = np.zeros_like(fields[0])
        for b in fields:
            dpred += b

        dpred += +Bigrf
        a = np.r_[xyzLoc[:, 0].min(), 0]
        b = np.r_[xyzLoc[:, 0].max(), 0]
        return plotProfile(xyzLoc, dobj, a, b, 10, pred=dpred, dType="2D")
Beispiel #2
0
    def MagSurvey2D(East, North, Width, Height, Azimuth, Length, Npts,
                    Profile):

        # Get the line extent from the 2D survey for now
        Azimuth /= 180.0 / np.pi
        Length /= 2.0 * 0.98

        a = [
            East - np.cos(-Azimuth) * Length, North - np.sin(-Azimuth) * Length
        ]

        b = [
            East + np.cos(-Azimuth) * Length, North + np.sin(-Azimuth) * Length
        ]

        xlim = East + np.asarray([-Width / 2.0, Width / 2.0])
        ylim = North + np.asarray([-Height / 2.0, Height / 2.0])

        # Re-sample the survey within the region
        rxLoc = survey.receiver_locations

        ind = np.all(
            [
                rxLoc[:, 0] > xlim[0],
                rxLoc[:, 0] < xlim[1],
                rxLoc[:, 1] > ylim[0],
                rxLoc[:, 1] < ylim[1],
            ],
            axis=0,
        )

        rxLoc = mag.receivers.Point(rxLoc[ind, :])
        srcField = mag.sources.SourceField(
            receiver_list=[rxLoc], parameters=survey.source_field.parameters)
        surveySim = mag.Survey(srcField)

        fig = plt.figure(figsize=(6, 9))
        ax1 = plt.subplot(2, 1, 1)
        plotMagSurvey2D(surveySim, dobj.dobs[ind], a, b, Npts, fig=fig, ax=ax1)

        if Profile:

            ax2 = plt.subplot(2, 1, 2)

            xyz = surveySim.receiver_locations
            plotProfile(xyz,
                        dobj.dobs[ind],
                        a,
                        b,
                        Npts,
                        pred=None,
                        fig=fig,
                        ax=ax2)

        return surveySim
Beispiel #3
0
    def setUp(self):

        # Define inducing field and sphere parameters
        H0 = (50000.0, 60.0, 250.0)
        # H0 = (50000., 90., 0.)
        self.b0 = mag.analytics.IDTtoxyz(-H0[1], H0[2], H0[0])
        self.rad = 2.0
        self.chi = 0.01

        # Define a mesh
        cs = 0.2
        hxind = [(cs, 21)]
        hyind = [(cs, 21)]
        hzind = [(cs, 21)]
        mesh = discretize.TensorMesh([hxind, hyind, hzind], "CCC")

        # Get cells inside the sphere
        sph_ind = getIndicesSphere([0.0, 0.0, 0.0], self.rad, mesh.gridCC)

        # Adjust susceptibility for volume difference
        Vratio = (4.0 / 3.0 * np.pi * self.rad**3.0) / (np.sum(sph_ind) *
                                                        cs**3.0)
        model = np.ones(mesh.nC) * self.chi * Vratio
        self.model = model[sph_ind]

        # Creat reduced identity map for Linear Pproblem
        idenMap = maps.IdentityMap(nP=int(sum(sph_ind)))

        # Create plane of observations
        xr = np.linspace(-20, 20, nx)
        yr = np.linspace(-20, 20, ny)
        self.xr = xr
        self.yr = yr
        X, Y = np.meshgrid(xr, yr)
        components = ["bx", "by", "bz", "tmi"]

        # Move obs plane 2 radius away from sphere
        Z = np.ones((xr.size, yr.size)) * 2.0 * self.rad
        self.locXyz = np.c_[utils.mkvc(X), utils.mkvc(Y), utils.mkvc(Z)]
        rxLoc = mag.Point(self.locXyz, components=components)
        srcField = mag.SourceField([rxLoc], parameters=H0)
        self.survey = mag.Survey(srcField)

        self.sim = mag.Simulation3DIntegral(
            mesh,
            survey=self.survey,
            chiMap=idenMap,
            actInd=sph_ind,
            store_sensitivities="forward_only",
        )
Beispiel #4
0
def createMagSurvey(xyzd, B):
    """
        Create SimPEG magnetic survey pbject

        INPUT
        :param array: xyzd, n-by-4 array of observation points and data
        :param array: B, 1-by-3 array of inducing field param [|B|, Inc, Dec]
    """

    rxLoc = mag.receivers.Point(xyzd[:, :3])
    source_field = mag.sources.SourceField(receiver_list=[rxLoc], parameters=B)
    survey = mag.Survey(source_field)
    dobj = data.Data(survey, xyzd[:, 3])

    return survey, dobj
Beispiel #5
0
    def setUp(self):

        Inc = 45.0
        Dec = 45.0
        Btot = 51000
        H0 = (Btot, Inc, Dec)

        self.b0 = mag.analytics.IDTtoxyz(-Inc, Dec, Btot)

        cs = 25.0
        hxind = [(cs, 5, -1.3), (cs / 2.0, 41), (cs, 5, 1.3)]
        hyind = [(cs, 5, -1.3), (cs / 2.0, 41), (cs, 5, 1.3)]
        hzind = [(cs, 5, -1.3), (cs / 2.0, 40), (cs, 5, 1.3)]
        M = discretize.TensorMesh([hxind, hyind, hzind], "CCC")

        chibkg = 0.0
        self.chiblk = 0.01
        chi = np.ones(M.nC) * chibkg

        self.rad = 100
        self.sphere_center = [0.0, 0.0, 0.0]
        sph_ind = getIndicesSphere(self.sphere_center, self.rad, M.gridCC)
        chi[sph_ind] = self.chiblk

        xr = np.linspace(-300, 300, 41)
        yr = np.linspace(-300, 300, 41)
        X, Y = np.meshgrid(xr, yr)
        Z = np.ones((xr.size, yr.size)) * 150
        components = ["bx", "by", "bz"]
        self.xr = xr
        self.yr = yr
        self.rxLoc = np.c_[utils.mkvc(X), utils.mkvc(Y), utils.mkvc(Z)]
        receivers = mag.Point(self.rxLoc, components=components)
        srcField = mag.SourceField([receivers], parameters=H0)

        self.survey = mag.Survey(srcField)

        self.sim = mag.simulation.Simulation3DDifferential(
            M,
            survey=self.survey,
            muMap=maps.ChiMap(M),
            solver=Pardiso,
        )
        self.M = M
        self.chi = chi
Beispiel #6
0
    def setUp(self):
        mesh = discretize.TensorMesh([4, 4, 4])

        # Magnetic inducing field parameter (A,I,D)
        B = [50000, 90, 0]

        # Create a MAGsurvey
        rx = mag.Point(np.vstack([[0.25, 0.25, 0.25], [-0.25, -0.25, 0.25]]))
        srcField = mag.SourceField([rx], parameters=(B[0], B[1], B[2]))
        survey = mag.Survey(srcField)

        # Create the forward model operator
        sim = mag.Simulation3DIntegral(mesh,
                                       survey=survey,
                                       chiMap=maps.IdentityMap(mesh))

        # Compute forward model some data
        m = np.random.rand(mesh.nC)
        data = sim.make_synthetic_data(m, add_noise=True)

        reg = regularization.Sparse(mesh)
        reg.mref = np.zeros(mesh.nC)
        reg.norms = np.c_[0, 1, 1, 1]
        reg.eps_p, reg.eps_q = 1e-3, 1e-3

        # Data misfit function
        dmis = data_misfit.L2DataMisfit(data)
        dmis.W = 1.0 / data.relative_error

        # Add directives to the inversion
        opt = optimization.ProjectedGNCG(maxIter=2,
                                         lower=-10.0,
                                         upper=10.0,
                                         maxIterCG=2)

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

        self.mesh = mesh
        self.invProb = invProb
        self.sim = sim
Beispiel #7
0
    def setUp(self):

        np.random.seed(0)

        # First we need to define the direction of the inducing field
        # As a simple case, we pick a vertical inducing field of magnitude
        # 50,000nT.
        # From old convention, field orientation is given as an
        # azimuth from North (positive clockwise)
        # and dip from the horizontal (positive downward).
        H0 = (50000.0, 90.0, 0.0)

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

        # Create grid of points for topography
        # Lets create a simple Gaussian topo and set the active cells
        [xx, yy] = np.meshgrid(np.linspace(-200.0, 200.0, 50),
                               np.linspace(-200.0, 200.0, 50))

        b = 100
        A = 50
        zz = A * np.exp(-0.5 * ((xx / b)**2.0 + (yy / b)**2.0))

        # 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.0, 100.0, 20)
        yr = np.linspace(-100.0, 100.0, 20)
        X, Y = np.meshgrid(xr, yr)
        Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 5

        # Create a MAGsurvey
        xyzLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)]
        rxLoc = mag.Point(xyzLoc)
        srcField = mag.SourceField([rxLoc], parameters=H0)
        survey = mag.Survey(srcField)

        # self.mesh.finalize()
        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())

        # We can now create a susceptibility model and generate data
        # Lets start with a simple block in half-space
        self.model = utils.model_builder.addBlock(
            self.mesh.gridCC,
            np.zeros(self.mesh.nC),
            np.r_[-20, -20, -15],
            np.r_[20, 20, 20],
            0.05,
        )[actv]

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

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

        # Create the forward model operator
        sim = mag.Simulation3DIntegral(
            self.mesh,
            survey=survey,
            chiMap=idenMap,
            actInd=actv,
            store_sensitivities="ram",
        )
        self.sim = sim
        data = sim.make_synthetic_data(self.model,
                                       relative_error=0.0,
                                       noise_floor=1.0,
                                       add_noise=True)

        # Create a regularization
        reg = regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap)
        reg.norms = np.c_[0, 0, 0, 0]

        reg.mref = np.zeros(nC)

        # Data misfit function
        dmis = data_misfit.L2DataMisfit(simulation=sim, data=data)

        # Add directives to the inversion
        opt = optimization.ProjectedGNCG(
            maxIter=10,
            lower=0.0,
            upper=10.0,
            maxIterLS=5,
            maxIterCG=5,
            tolCG=1e-4,
            stepOffBoundsFact=1e-4,
        )

        invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=1e6)

        # 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,
                                      max_irls_iterations=20,
                                      beta_tol=1e-1,
                                      beta_search=False)
        update_Jacobi = directives.UpdatePreconditioner()
        sensitivity_weights = directives.UpdateSensitivityWeights()
        self.inv = inversion.BaseInversion(
            invProb, directiveList=[IRLS, sensitivity_weights, update_Jacobi])
    def setUp(self):
        np.random.seed(0)
        H0 = (50000.0, 90.0, 0.0)

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

        # 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.0 + (yy / b)**2.0))

        # 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.0, 100.0, 20)
        yr = np.linspace(-100.0, 100.0, 20)
        X, Y = np.meshgrid(xr, yr)
        Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 5

        # Create a MAGsurvey
        xyzLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)]
        rxLoc = mag.Point(xyzLoc)
        srcField = mag.SourceField([rxLoc], parameters=H0)
        survey = mag.Survey(srcField)

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

        mesh = mesh_builder_xyz(xyzLoc,
                                h,
                                padding_distance=padDist,
                                depth_core=100,
                                mesh_type="tree")
        mesh = refine_tree_xyz(mesh,
                               topo,
                               method="surface",
                               octree_levels=[4, 4],
                               finalize=True)
        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.mat_utils.dip_azimuth2cartesian(M[0], M[1])

        # Get the indicies of the magnetized block
        ind = utils.model_builder.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
        sim = mag.Simulation3DIntegral(
            self.mesh,
            survey=survey,
            model_type="vector",
            chiMap=idenMap,
            actInd=actv,
            store_sensitivities="disk",
        )
        self.sim = sim

        # Compute some data and add some random noise
        data = sim.make_synthetic_data(utils.mkvc(self.model),
                                       relative_error=0.0,
                                       noise_floor=5.0,
                                       add_noise=True)

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

        # 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_s = regularization.Sparse(mesh, indActive=actv, mapping=wires.s)
        reg_s.mref = np.zeros(3 * nC)

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

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

        # Data misfit function
        dmis = data_misfit.L2DataMisfit(simulation=sim, data=data)
        # dmis.W = 1./survey.std

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

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

        # A list of directive to control the inverson
        betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e1)

        # 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,
                                      max_irls_iterations=0,
                                      beta_tol=5e-1)

        # Pre-conditioner
        update_Jacobi = directives.UpdatePreconditioner()
        sensitivity_weights = directives.UpdateSensitivityWeights(
            everyIter=False)
        inv = inversion.BaseInversion(
            invProb,
            directiveList=[sensitivity_weights, IRLS, update_Jacobi, betaest])

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

        sim.chiMap = maps.SphericalSystem(nP=nC * 3)
        self.mstart = sim.chiMap.inverse(mrec_MVIC)
        dmis.simulation.model = self.mstart
        beta = invProb.beta

        # 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, 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.0  # No reference angle
        reg_t.space = "spherical"
        reg_t.norms = np.c_[2.0, 0.0, 0.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.0  # No reference angle
        reg_p.space = "spherical"
        reg_p.norms = np.c_[2.0, 0.0, 0.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=5,
            lower=Lbound,
            upper=Ubound,
            maxIterLS=5,
            maxIterCG=5,
            tolCG=1e-3,
            stepOffBoundsFact=1e-3,
        )
        opt.approxHinv = None

        invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=beta)

        # Here is where the norms are applied
        IRLS = directives.Update_IRLS(
            f_min_change=1e-4,
            max_irls_iterations=5,
            minGNiter=1,
            beta_tol=0.5,
            coolingRate=1,
            coolEps_q=True,
            sphericalDomain=True,
        )

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

        self.inv = inversion.BaseInversion(
            invProb,
            directiveList=[
                ProjSpherical, IRLS, sensitivity_weights, update_Jacobi
            ],
        )
    def setUp(self):

        np.random.seed(0)

        # Define the inducing field parameter
        H0 = (50000, 90, 0)

        # Create a mesh
        dx = 5.0

        hxind = [(dx, 5, -1.3), (dx, 5), (dx, 5, 1.3)]
        hyind = [(dx, 5, -1.3), (dx, 5), (dx, 5, 1.3)]
        hzind = [(dx, 5, -1.3), (dx, 6)]

        self.mesh = discretize.TensorMesh([hxind, hyind, hzind], "CCC")

        # Get index of the center
        midx = int(self.mesh.nCx / 2)
        midy = int(self.mesh.nCy / 2)

        # Lets create a simple Gaussian topo and set the active cells
        [xx, yy] = np.meshgrid(self.mesh.vectorNx, self.mesh.vectorNy)
        zz = -np.exp((xx**2 + yy**2) / 75**2) + self.mesh.vectorNz[-1]

        # Go from topo to actv cells
        topo = np.c_[utils.mkvc(xx), utils.mkvc(yy), utils.mkvc(zz)]
        actv = utils.surface2ind_topo(self.mesh, topo, "N")
        actv = np.where(actv)[0]

        # Create active map to go from reduce space to full
        self.actvMap = maps.InjectActiveCells(self.mesh, actv, -100)
        nC = len(actv)

        # Create and array of observation points
        xr = np.linspace(-20.0, 20.0, 20)
        yr = np.linspace(-20.0, 20.0, 20)
        X, Y = np.meshgrid(xr, yr)

        # Move the observation points 5m above the topo
        Z = -np.exp((X**2 + Y**2) / 75**2) + self.mesh.vectorNz[-1] + 5.0

        # Create a MAGsurvey
        rxLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)]
        rxLoc = mag.Point(rxLoc)
        srcField = mag.SourceField([rxLoc], parameters=H0)
        survey = mag.Survey(srcField)

        # We can now create a susceptibility model and generate data
        # Here a simple block in half-space
        model = np.zeros((self.mesh.nCx, self.mesh.nCy, self.mesh.nCz))
        model[(midx - 2):(midx + 2), (midy - 2):(midy + 2), -6:-2] = 0.02
        model = utils.mkvc(model)
        self.model = model[actv]

        # Create active map to go from reduce set to full
        self.actvMap = maps.InjectActiveCells(self.mesh, actv, -100)

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

        # Create the forward model operator
        sim = mag.Simulation3DIntegral(
            self.mesh,
            survey=survey,
            chiMap=idenMap,
            actInd=actv,
            store_sensitivities="disk",
        )
        self.sim = sim

        # Compute linear forward operator and compute some data
        data = sim.make_synthetic_data(self.model,
                                       relative_error=0.0,
                                       noise_floor=1.0,
                                       add_noise=True)

        # Create a regularization
        reg = regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap)
        reg.norms = np.c_[0, 0, 0, 0]
        reg.gradientType = "component"
        # reg.eps_p, reg.eps_q = 1e-3, 1e-3

        # Data misfit function
        dmis = data_misfit.L2DataMisfit(simulation=sim, data=data)
        # dmis.W = 1/wd

        # Add directives to the inversion
        opt = optimization.ProjectedGNCG(maxIter=100,
                                         lower=0.0,
                                         upper=1.0,
                                         maxIterLS=20,
                                         maxIterCG=10,
                                         tolCG=1e-3)

        invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
        betaest = directives.BetaEstimate_ByEig()

        # Here is where the norms are applied
        IRLS = directives.Update_IRLS(f_min_change=1e-4, minGNiter=1)
        update_Jacobi = directives.UpdatePreconditioner()
        sensitivity_weights = directives.UpdateSensitivityWeights(
            everyIter=False)
        self.inv = inversion.BaseInversion(
            invProb,
            directiveList=[IRLS, sensitivity_weights, betaest, update_Jacobi])
Beispiel #10
0
def run(plotIt=True):

    H0 = (50000.0, 90.0, 0.0)

    # Create a mesh
    dx = 5.0

    hxind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)]
    hyind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)]
    hzind = [(dx, 5, -1.3), (dx, 10)]

    mesh = discretize.TensorMesh([hxind, hyind, hzind], "CCC")

    # Lets create a simple Gaussian topo and set the active cells
    [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy)
    zz = -np.exp((xx ** 2 + yy ** 2) / 75 ** 2) + mesh.vectorNz[-1]

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

    # Go from topo to array of indices of active cells
    actv = utils.surface2ind_topo(mesh, topo, "N")
    actv = np.where(actv)[0]

    # Create and array of observation points
    xr = np.linspace(-20.0, 20.0, 20)
    yr = np.linspace(-20.0, 20.0, 20)
    X, Y = np.meshgrid(xr, yr)

    # Move the observation points 5m above the topo
    Z = -np.exp((X ** 2 + Y ** 2) / 75 ** 2) + mesh.vectorNz[-1] + 5.0

    # Create a MAGsurvey
    rxLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)]
    rxLoc = magnetics.Point(rxLoc)
    srcField = magnetics.SourceField([rxLoc], parameters=H0)
    survey = magnetics.Survey(srcField)

    # We can now create a susceptibility model and generate data
    model = np.zeros(mesh.nC)

    # Change values in half the domain
    model[mesh.gridCC[:, 0] < 0] = 0.01

    # Add a block in half-space
    model = utils.model_builder.addBlock(
        mesh.gridCC, model, np.r_[-10, -10, 20], np.r_[10, 10, 40], 0.05
    )

    model = utils.mkvc(model)
    model = model[actv]

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

    # Create reduced identity map
    idenMap = maps.IdentityMap(nP=len(actv))

    # Create the forward model operator
    prob = magnetics.Simulation3DIntegral(
        mesh,
        survey=survey,
        chiMap=idenMap,
        actInd=actv,
        store_sensitivities="forward_only",
    )

    # Compute linear forward operator and compute some data
    data = prob.make_synthetic_data(
        model, relative_error=0.0, noise_floor=1, add_noise=True
    )

    # Create a homogenous maps for the two domains
    domains = [mesh.gridCC[actv, 0] < 0, mesh.gridCC[actv, 0] >= 0]
    homogMap = maps.SurjectUnits(domains)

    # Create a wire map for a second model space, voxel based
    wires = maps.Wires(("h**o", len(domains)), ("hetero", len(actv)))

    # Create Sum map
    sumMap = maps.SumMap([homogMap * wires.h**o, wires.hetero])

    # Create the forward model operator
    prob = magnetics.Simulation3DIntegral(
        mesh, survey=survey, chiMap=sumMap, actInd=actv, store_sensitivities="ram"
    )

    # Make depth weighting
    wr = np.zeros(sumMap.shape[1])
    print(prob.nC)
    # print(prob.M.shape) # why does this reset nC
    G = prob.G

    # Take the cell number out of the scaling.
    # Want to keep high sens for large volumes
    scale = utils.sdiag(
        np.r_[utils.mkvc(1.0 / homogMap.P.sum(axis=0)), np.ones_like(actv)]
    )

    for ii in range(survey.nD):
        wr += (
            (prob.G[ii, :] * prob.chiMap.deriv(np.ones(sumMap.shape[1]) * 1e-4) * scale)
            / data.standard_deviation[ii]
        ) ** 2.0

    # Scale the model spaces independently
    wr[wires.h**o.index] /= np.max((wires.h**o * wr))
    wr[wires.hetero.index] /= np.max(wires.hetero * wr)
    wr = wr ** 0.5

    ## Create a regularization
    # For the homogeneous model
    regMesh = discretize.TensorMesh([len(domains)])

    reg_m1 = regularization.Sparse(regMesh, mapping=wires.h**o)
    reg_m1.cell_weights = wires.h**o * wr
    reg_m1.norms = np.c_[0, 2, 2, 2]
    reg_m1.mref = np.zeros(sumMap.shape[1])

    # Regularization for the voxel model
    reg_m2 = regularization.Sparse(mesh, indActive=actv, mapping=wires.hetero)
    reg_m2.cell_weights = wires.hetero * wr
    reg_m2.norms = np.c_[0, 1, 1, 1]
    reg_m2.mref = np.zeros(sumMap.shape[1])

    reg = reg_m1 + reg_m2

    # Data misfit function
    dmis = data_misfit.L2DataMisfit(simulation=prob, data=data)

    # Add directives to the inversion
    opt = optimization.ProjectedGNCG(
        maxIter=100,
        lower=0.0,
        upper=1.0,
        maxIterLS=20,
        maxIterCG=10,
        tolCG=1e-3,
        tolG=1e-3,
        eps=1e-6,
    )
    invProb = inverse_problem.BaseInvProblem(dmis, reg, opt)
    betaest = directives.BetaEstimate_ByEig()

    # Here is where the norms are applied
    # Use pick a threshold parameter empirically based on the distribution of
    #  model parameters
    IRLS = directives.Update_IRLS(f_min_change=1e-3, minGNiter=1)
    update_Jacobi = directives.UpdatePreconditioner()
    inv = inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi])

    # Run the inversion
    m0 = np.ones(sumMap.shape[1]) * 1e-4  # Starting model
    prob.model = m0
    mrecSum = inv.run(m0)
    if plotIt:

        mesh.plot_3d_slicer(
            actvMap * model,
            aspect="equal",
            zslice=30,
            pcolorOpts={"cmap": "inferno_r"},
            transparent="slider",
        )

        mesh.plot_3d_slicer(
            actvMap * sumMap * mrecSum,
            aspect="equal",
            zslice=30,
            pcolorOpts={"cmap": "inferno_r"},
            transparent="slider",
        )