Exemple #1
0
    def test_validation_in_inversion(self):
        betaest = directives.BetaEstimate_ByEig()

        # Here is where the norms are applied
        IRLS = directives.Update_IRLS(f_min_change=1e-4,
                                      minGNiter=3,
                                      beta_tol=1e-2)

        update_Jacobi = directives.UpdatePreconditioner()
        sensitivity_weights = directives.UpdateSensitivityWeights()
        with self.assertRaises(AssertionError):
            # validation should happen and this will fail
            # (IRLS needs to be before update_Jacobi)
            inv = inversion.BaseInversion(
                self.invProb, directiveList=[betaest, update_Jacobi, IRLS])

        with self.assertRaises(AssertionError):
            # validation should happen and this will fail
            # (sensitivity_weights needs to be before betaest)
            inv = inversion.BaseInversion(
                self.invProb, directiveList=[betaest, sensitivity_weights])

        with self.assertRaises(AssertionError):
            # validation should happen and this will fail
            # (sensitivity_weights needs to be before update_Jacobi)
            inv = inversion.BaseInversion(self.invProb)
            inv.directiveList = [update_Jacobi, sensitivity_weights]
Exemple #2
0
def run_inversion(
    m0,
    simulation,
    data,
    actind,
    mesh,
    maxIter=15,
    beta0_ratio=1e0,
    coolingFactor=5,
    coolingRate=2,
    upper=np.inf,
    lower=-np.inf,
    use_sensitivity_weight=True,
    alpha_s=1e-4,
    alpha_x=1.0,
    alpha_y=1.0,
    alpha_z=1.0,
):
    """
    Run DC inversion
    """
    dmisfit = data_misfit.L2DataMisfit(simulation=simulation, data=data)
    # 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.Tikhonov(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

    opt = optimization.ProjectedGNCG(maxIter=maxIter, upper=upper, lower=lower)
    invProb = inverse_problem.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
    update_Jacobi = directives.UpdatePreconditioner()
    if use_sensitivity_weight:
        updateSensW = directives.UpdateSensitivityWeights()
        directiveList = [beta, target, updateSensW, update_Jacobi, betaest]
    else:
        directiveList = [beta, target, update_Jacobi, betaest]
    inv = inversion.BaseInversion(invProb, directiveList=directiveList)
    opt.LSshorten = 0.5
    opt.remember("xc")

    # Run inversion
    mopt = inv.run(m0)
    return mopt, invProb.dpred
Exemple #3
0
dc_inverse_problem = inverse_problem.BaseInvProblem(dc_data_misfit,
                                                    dc_regularization,
                                                    dc_optimization)

#################################################
# Define DC Inversion Directives
# ------------------------------
#
# Here we define any directives that are carried out during the inversion. This
# includes the cooling schedule for the trade-off parameter (beta), stopping
# criteria for the inversion and saving inversion results at each iteration.
#
#

# Apply and update sensitivity weighting as the model updates
update_sensitivity_weighting = directives.UpdateSensitivityWeights()

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

# Set the rate of reduction in trade-off parameter (beta) each time the
# the inverse problem is solved. And set the number of Gauss-Newton iterations
# for each trade-off paramter value.
beta_schedule = directives.BetaSchedule(coolingFactor=2.5, coolingRate=2)

# Options for outputting recovered models and predicted data for each beta.
save_iteration = directives.SaveOutputEveryIteration(save_txt=False)

# Setting a stopping criteria for the inversion.
target_misfit = directives.TargetMisfit(chifact=1)
Exemple #4
0
    coolEpsFact=1.5,
    beta_tol=1e-2,
)

# Defining the fractional decrease in beta and the number of Gauss-Newton solves
# for each beta value.
beta_schedule = directives.BetaSchedule(coolingFactor=5, coolingRate=1)

# Options for outputting recovered models and predicted data for each beta.
save_iteration = directives.SaveOutputEveryIteration(save_txt=False)

# Updating the preconditionner if it is model dependent.
update_jacobi = directives.UpdatePreconditioner()

# Add sensitivity weights
sensitivity_weights = directives.UpdateSensitivityWeights(everyIter=False)

# The directives are defined as a list.
directives_list = [
    update_IRLS,
    sensitivity_weights,
    starting_beta,
    beta_schedule,
    save_iteration,
    update_jacobi,
]

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

#######################################################################
# Define DC Inversion Directives
# ------------------------------
#
# Here we define any directives that are carried out during the inversion. This
# includes the cooling schedule for the trade-off parameter (beta), stopping
# criteria for the inversion and saving inversion results at each iteration.
#


# Apply and update sensitivity weighting as the model updates
update_sensitivity_weighting = directives.UpdateSensitivityWeights()

# Reach target misfit for L2 solution, then use IRLS until model stops changing.
update_IRLS = directives.Update_IRLS(
    max_irls_iterations=20, minGNiter=1, beta_search=False, fix_Jmatrix=True
)

# 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 preconditionner
update_Jacobi = directives.UpdatePreconditioner()

# Options for outputting recovered models and predicted data for each beta.
save_iteration = directives.SaveOutputEveryIteration(save_txt=False)
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.0, 200.0
    ymin, ymax = 0.0, 0.0
    zmin, zmax = 0, 0
    endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]])
    # Generate DC survey object
    survey = gen_DCIPsurvey(endl,
                            survey_type=survey_type,
                            dim=2,
                            a=10,
                            b=10,
                            n=10)
    survey = IO.from_ambn_locations_to_survey(
        survey.locations_a,
        survey.locations_b,
        survey.locations_m,
        survey.locations_n,
        survey_type,
        data_dc_type="volt",
    )

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

    # Build a conductivity model
    blk_inds_c = utils.model_builder.getIndicesSphere(np.r_[60.0, -25.0], 12.5,
                                                      mesh.gridCC)
    blk_inds_r = utils.model_builder.getIndicesSphere(np.r_[140.0, -25.0],
                                                      12.5, mesh.gridCC)
    layer_inds = mesh.gridCC[:, 1] > -5.0
    sigma = np.ones(mesh.nC) * 1.0 / 100.0
    sigma[blk_inds_c] = 1.0 / 10.0
    sigma[blk_inds_r] = 1.0 / 1000.0
    sigma[~actind] = 1.0 / 1e8
    rho = 1.0 / 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.Simulation2DNodal(mesh,
                               survey=survey,
                               rhoMap=mapping,
                               storeJ=True,
                               Solver=Solver,
                               verbose=True)

    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
    data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True)

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

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure()
        out = hist(data.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.0)

    # Set standard_deviation
    # floor (10 ohm-m)
    eps = 1.0
    # percentage
    relative = 0.05
    dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data)
    uncert = abs(data.dobs) * relative + eps
    dmisfit.standard_deviation = 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 = inverse_problem.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, target, updateSensW, betaest, 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()
Exemple #7
0
    def setUp(self):

        ndv = -100
        # Create a self.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
        locXYZ = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)]
        rxLoc = gravity.Point(locXYZ)
        srcField = gravity.SourceField([rxLoc])
        survey = gravity.Survey(srcField)

        # We can now create a density 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.5
        model = utils.mkvc(model)
        self.model = model[actv]

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

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

        # Create the forward model operator
        sim = gravity.Simulation3DIntegral(
            self.mesh,
            survey=survey,
            rhoMap=idenMap,
            actInd=actv,
            store_sensitivities="ram",
        )

        # Compute linear forward operator and compute some data
        # computing sensitivities to ram is best using dask processes
        with dask.config.set(scheduler="processes"):
            data = sim.make_synthetic_data(self.model,
                                           relative_error=0.0,
                                           noise_floor=0.001,
                                           add_noise=True)
        print(sim.G)

        # 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 = 5e-2, 1e-2

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

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

        # 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, update_Jacobi])
        self.sim = sim
Exemple #8
0
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.0, 200.0
    ymin, ymax = 0.0, 0.0
    zmin, zmax = 0, 0
    endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]])
    # Generate DC survey object
    survey = DCutils.gen_DCIPsurvey(endl,
                                    survey_type=survey_type,
                                    dim=2,
                                    a=10,
                                    b=10,
                                    n=10)
    survey = IO.from_ambn_locations_to_survey(
        survey.locations_a,
        survey.locations_b,
        survey.locations_m,
        survey.locations_n,
        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.0])
    survey.drape_electrodes_on_topography(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.Simulation2DNodal(mesh,
                               survey=survey,
                               rhoMap=mapping,
                               storeJ=True,
                               solver=Solver)

    # Make synthetic DC data with 5% Gaussian noise
    data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True)

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

    # Show apparent resisitivty histogram
    fig = plt.figure()
    out = hist(data.dobs / IO.G, bins=20)
    plt.show()
    # Set standard_deviation
    # floor
    eps = 10**(-3.2)
    # percentage
    relative = 0.05
    dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data)
    uncert = abs(data.dobs) * relative + eps
    dmisfit.standard_deviation = uncert

    # Map for a regularization
    mesh_1d = discretize.TensorMesh([parametric_block.nP])
    # Related to inversion
    reg = regularization.Simple(mesh_1d, alpha_x=0.0)
    opt = optimization.InexactGaussNewton(maxIter=10)
    invProb = inverse_problem.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.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()
Exemple #9
0
def run(plotIt=True):

    # Define the inducing field parameter
    H0 = (50000, 90, 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 = TensorMesh([hxind, hyind, hzind], "CCC")

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

    # 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]
    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) + 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.receivers.Point(rxLoc, components=["tmi"])
    srcField = magnetics.sources.SourceField(receiver_list=[rxLoc],
                                             parameters=H0)
    survey = magnetics.survey.Survey(srcField)

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

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

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

    # Create the forward model operator
    simulation = magnetics.simulation.Simulation3DIntegral(
        survey=survey,
        mesh=mesh,
        chiMap=idenMap,
        actInd=actv,
    )

    # Compute linear forward operator and compute some data
    d = simulation.dpred(model)

    # Add noise and uncertainties
    # We add some random Gaussian noise (1nT)
    synthetic_data = d + np.random.randn(len(d))
    wd = np.ones(len(synthetic_data)) * 1.0  # Assign flat uncertainties

    data_object = data.Data(survey, dobs=synthetic_data, noise_floor=wd)

    # Create a regularization
    reg = regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
    reg.mref = np.zeros(nC)
    reg.norms = np.c_[0, 0, 0, 0]
    # reg.eps_p, reg.eps_q = 1e-0, 1e-0

    # Create sensitivity weights from our linear forward operator
    rxLoc = survey.source_field.receiver_list[0].locations
    m0 = np.ones(nC) * 1e-4  # Starting model

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

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

    # 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, max_irls_iterations=40)
    saveDict = directives.SaveOutputEveryIteration(save_txt=False)
    update_Jacobi = directives.UpdatePreconditioner()
    # Add sensitivity weights
    sensitivity_weights = directives.UpdateSensitivityWeights(everyIter=False)

    inv = inversion.BaseInversion(
        invProb,
        directiveList=[
            sensitivity_weights, IRLS, betaest, update_Jacobi, saveDict
        ],
    )

    # Run the inversion
    mrec = inv.run(m0)

    if plotIt:
        # Here is the recovered susceptibility model
        ypanel = midx
        zpanel = -5
        m_l2 = actvMap * invProb.l2model
        m_l2[m_l2 == -100] = np.nan

        m_lp = actvMap * mrec
        m_lp[m_lp == -100] = np.nan

        m_true = actvMap * model
        m_true[m_true == -100] = np.nan

        # Plot the data
        utils.plot_utils.plot2Ddata(rxLoc, d)

        plt.figure()

        # Plot L2 model
        ax = plt.subplot(321)
        mesh.plotSlice(
            m_l2,
            ax=ax,
            normal="Z",
            ind=zpanel,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]),
            color="w",
        )
        plt.title("Plan l2-model.")
        plt.gca().set_aspect("equal")
        plt.ylabel("y")
        ax.xaxis.set_visible(False)
        plt.gca().set_aspect("equal", adjustable="box")

        # Vertica section
        ax = plt.subplot(322)
        mesh.plotSlice(
            m_l2,
            ax=ax,
            normal="Y",
            ind=midx,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]),
            color="w",
        )
        plt.title("E-W l2-model.")
        plt.gca().set_aspect("equal")
        ax.xaxis.set_visible(False)
        plt.ylabel("z")
        plt.gca().set_aspect("equal", adjustable="box")

        # Plot Lp model
        ax = plt.subplot(323)
        mesh.plotSlice(
            m_lp,
            ax=ax,
            normal="Z",
            ind=zpanel,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]),
            color="w",
        )
        plt.title("Plan lp-model.")
        plt.gca().set_aspect("equal")
        ax.xaxis.set_visible(False)
        plt.ylabel("y")
        plt.gca().set_aspect("equal", adjustable="box")

        # Vertical section
        ax = plt.subplot(324)
        mesh.plotSlice(
            m_lp,
            ax=ax,
            normal="Y",
            ind=midx,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]),
            color="w",
        )
        plt.title("E-W lp-model.")
        plt.gca().set_aspect("equal")
        ax.xaxis.set_visible(False)
        plt.ylabel("z")
        plt.gca().set_aspect("equal", adjustable="box")

        # Plot True model
        ax = plt.subplot(325)
        mesh.plotSlice(
            m_true,
            ax=ax,
            normal="Z",
            ind=zpanel,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]),
            color="w",
        )
        plt.title("Plan true model.")
        plt.gca().set_aspect("equal")
        plt.xlabel("x")
        plt.ylabel("y")
        plt.gca().set_aspect("equal", adjustable="box")

        # Vertical section
        ax = plt.subplot(326)
        mesh.plotSlice(
            m_true,
            ax=ax,
            normal="Y",
            ind=midx,
            grid=True,
            clim=(model.min(), model.max()),
        )
        plt.plot(
            ([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]),
            color="w",
        )
        plt.title("E-W true model.")
        plt.gca().set_aspect("equal")
        plt.xlabel("x")
        plt.ylabel("z")
        plt.gca().set_aspect("equal", adjustable="box")

        # Plot convergence curves
        fig, axs = plt.figure(), plt.subplot()
        axs.plot(saveDict.phi_d, "k", lw=2)
        axs.plot(
            np.r_[IRLS.iterStart, IRLS.iterStart],
            np.r_[0, np.max(saveDict.phi_d)],
            "k:",
        )

        twin = axs.twinx()
        twin.plot(saveDict.phi_m, "k--", lw=2)
        axs.text(
            IRLS.iterStart,
            0,
            "IRLS Steps",
            va="bottom",
            ha="center",
            rotation="vertical",
            size=12,
            bbox={"facecolor": "white"},
        )

        axs.set_ylabel("$\phi_d$", size=16, rotation=0)
        axs.set_xlabel("Iterations", size=14)
        twin.set_ylabel("$\phi_m$", size=16, rotation=0)
# Add directives to the inversion
opt = optimization.ProjectedGNCG(maxIter=10,
                                 lower=-10,
                                 upper=10.0,
                                 maxIterLS=20,
                                 maxIterCG=20,
                                 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)

# Add sensitivity weights
sensitivity_weights = directives.UpdateSensitivityWeights()

# Here is where the norms are applied
# Use a threshold parameter empirically based on the distribution of
#  model parameters
IRLS = directives.Update_IRLS(f_min_change=1e-3,
                              max_irls_iterations=2,
                              beta_tol=5e-1)

# Pre-conditioner
update_Jacobi = directives.UpdatePreconditioner()

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

# Run the inversion
Exemple #11
0
def setup_and_run_std_inv(mesh, dc_survey, dc_data, std_dc, conductivity_map,
                          ind_active, starting_conductivity_model):
    """Code to setup and run a standard inversion.

    Parameters
    ----------
    mesh : TYPE
        DESCRIPTION.
    dc_survey : TYPE
        DESCRIPTION.
    dc_data : TYPE
        DESCRIPTION.
    std_dc : TYPE
        DESCRIPTION.
    conductivity_map : TYPE
        DESCRIPTION.
    ind_active : TYPE
        DESCRIPTION.
    starting_conductivity_model : TYPE
        DESCRIPTION.

    Returns
    -------
    save_iteration : TYPE
        DESCRIPTION.
    save_dict_iteration : TYPE
        DESCRIPTION.
    """
    # Add standard deviations to data object
    dc_data.standard_deviation = std_dc

    # Define the simulation (physics of the problem)
    dc_simulation = dc.simulation_2d.Simulation2DNodal(
        mesh, survey=dc_survey, sigmaMap=conductivity_map, Solver=Solver)

    # Define the data misfit.
    dc_data_misfit = data_misfit.L2DataMisfit(data=dc_data,
                                              simulation=dc_simulation)

    # Define the regularization (model objective function)
    dc_regularization = regularization.Simple(mesh,
                                              indActive=ind_active,
                                              mref=starting_conductivity_model,
                                              alpha_s=0.01,
                                              alpha_x=1,
                                              alpha_y=1)

    # Define how the optimization problem is solved. Here we will use a
    # projected. Gauss-Newton approach that employs the conjugate gradient
    # solver.
    dc_optimization = optimization.ProjectedGNCG(maxIter=15,
                                                 lower=-np.inf,
                                                 upper=np.inf,
                                                 maxIterLS=20,
                                                 maxIterCG=10,
                                                 tolCG=1e-3)

    # Here we define the inverse problem that is to be solved
    dc_inverse_problem = inverse_problem.BaseInvProblem(
        dc_data_misfit, dc_regularization, dc_optimization)

    # Define inversion directives

    # Apply and update sensitivity weighting as the model updates
    update_sensitivity_weighting = directives.UpdateSensitivityWeights()

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

    # Set the rate of reduction in trade-off parameter (beta) each time the
    # the inverse problem is solved. And set the number of Gauss-Newton
    # iterations for each trade-off paramter value.
    beta_schedule = directives.BetaSchedule(coolingFactor=10, coolingRate=1)

    # Options for outputting recovered models and predicted data for each beta.
    save_iteration = directives.SaveOutputEveryIteration(save_txt=False)

    # save results from each iteration in a dict
    save_dict_iteration = directives.SaveOutputDictEveryIteration(
        saveOnDisk=False)

    directives_list = [
        update_sensitivity_weighting,
        starting_beta,
        beta_schedule,
        save_iteration,
        save_dict_iteration,
    ]

    # Here we combine the inverse problem and the set of directives
    dc_inversion = inversion.BaseInversion(dc_inverse_problem,
                                           directiveList=directives_list)

    # Run inversion
    _ = dc_inversion.run(starting_conductivity_model)

    return save_iteration, save_dict_iteration
Exemple #12
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
            ],
        )
Exemple #14
0
def run(plotIt=True, cleanAfterRun=True):

    # Start by downloading files from the remote repository
    # directory where the downloaded files are

    url = "https://storage.googleapis.com/simpeg/Chile_GRAV_4_Miller/Chile_GRAV_4_Miller.tar.gz"
    downloads = download(url, overwrite=True)
    basePath = downloads.split(".")[0]

    # unzip the tarfile
    tar = tarfile.open(downloads, "r")
    tar.extractall()
    tar.close()

    input_file = basePath + os.path.sep + "LdM_input_file.inp"
    # %% User input
    # Plotting parameters, max and min densities in g/cc
    vmin = -0.6
    vmax = 0.6

    # weight exponent for default weighting
    wgtexp = 3.0
    # %%
    # Read in the input file which included all parameters at once
    # (mesh, topo, model, survey, inv param, etc.)
    driver = GravityDriver_Inv(input_file)
    # %%
    # Now we need to create the survey and model information.

    # Access the mesh and survey information
    mesh = driver.mesh  #
    survey = driver.survey
    data_object = driver.data
    # [survey, data_object] = driver.survey

    # define gravity survey locations
    rxLoc = survey.source_field.receiver_list[0].locations

    # define gravity data and errors
    d = data_object.dobs

    # Get the active cells
    active = driver.activeCells
    nC = len(active)  # Number of active cells

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

    # Create static map
    static = driver.staticCells
    dynamic = driver.dynamicCells

    staticCells = maps.InjectActiveCells(None,
                                         dynamic,
                                         driver.m0[static],
                                         nC=nC)
    mstart = driver.m0[dynamic]

    # Get index of the center
    midx = int(mesh.nCx / 2)
    # %%
    # Now that we have a model and a survey we can build the linear system ...
    # Create the forward model operator
    simulation = gravity.simulation.Simulation3DIntegral(survey=survey,
                                                         mesh=mesh,
                                                         rhoMap=staticCells,
                                                         actInd=active)

    # %% Create inversion objects
    reg = regularization.Sparse(mesh,
                                indActive=active,
                                mapping=staticCells,
                                gradientType="total")
    reg.mref = driver.mref[dynamic]

    reg.norms = np.c_[0.0, 1.0, 1.0, 1.0]
    # reg.norms = driver.lpnorms

    # Specify how the optimization will proceed
    opt = optimization.ProjectedGNCG(
        maxIter=20,
        lower=driver.bounds[0],
        upper=driver.bounds[1],
        maxIterLS=10,
        maxIterCG=20,
        tolCG=1e-4,
    )

    # Define misfit function (obs-calc)
    dmis = data_misfit.L2DataMisfit(data=data_object, simulation=simulation)

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

    # Specify how the initial beta is found
    betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e-2)

    # IRLS sets up the Lp inversion problem
    # Set the eps parameter parameter in Line 11 of the
    # input file based on the distribution of model (DEFAULT = 95th %ile)
    IRLS = directives.Update_IRLS(f_min_change=1e-4,
                                  max_irls_iterations=40,
                                  coolEpsFact=1.5,
                                  beta_tol=5e-1)

    # Preconditioning refreshing for each IRLS iteration
    update_Jacobi = directives.UpdatePreconditioner()
    sensitivity_weights = directives.UpdateSensitivityWeights()

    # Create combined the L2 and Lp problem
    inv = inversion.BaseInversion(
        invProb,
        directiveList=[sensitivity_weights, IRLS, update_Jacobi, betaest])

    # %%
    # Run L2 and Lp inversion
    mrec = inv.run(mstart)

    if cleanAfterRun:
        os.remove(downloads)
        shutil.rmtree(basePath)

    # %%
    if plotIt:
        # Plot observed data
        # The sign of the data is flipped here for the change of convention
        # between Cartesian coordinate system (internal SimPEG format that
        # expects "positive up" gravity signal) and traditional gravity data
        # conventions (positive down). For example a traditional negative
        # gravity anomaly is described as "positive up" in Cartesian coordinates
        # and hence the sign needs to be flipped for use in SimPEG.
        plot2Ddata(rxLoc, -d)

        # %%
        # Write output model and data files and print misfit stats.

        # reconstructing l2 model mesh with air cells and active dynamic cells
        L2out = activeMap * invProb.l2model

        # reconstructing lp model mesh with air cells and active dynamic cells
        Lpout = activeMap * mrec

        # %%
        # Plot out sections and histograms of the smooth l2 model.
        # The ind= parameter is the slice of the model from top down.
        yslice = midx + 1
        L2out[L2out == -100] = np.nan  # set "air" to nan

        plt.figure(figsize=(10, 7))
        plt.suptitle("Smooth Inversion: Depth weight = " + str(wgtexp))
        ax = plt.subplot(221)
        dat1 = mesh.plotSlice(
            L2out,
            ax=ax,
            normal="Z",
            ind=-16,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.plot(
            np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]),
            c="gray",
            linestyle="--",
        )
        plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color="k", s=1)
        plt.title("Z: " + str(mesh.vectorCCz[-16]) + " m")
        plt.xlabel("Easting (m)")
        plt.ylabel("Northing (m)")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(dat1[0],
                          orientation="vertical",
                          ticks=np.linspace(vmin, vmax, 4))
        cb.set_label("Density (g/cc$^3$)")

        ax = plt.subplot(222)
        dat = mesh.plotSlice(
            L2out,
            ax=ax,
            normal="Z",
            ind=-27,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.plot(
            np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]),
            c="gray",
            linestyle="--",
        )
        plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color="k", s=1)
        plt.title("Z: " + str(mesh.vectorCCz[-27]) + " m")
        plt.xlabel("Easting (m)")
        plt.ylabel("Northing (m)")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(dat1[0],
                          orientation="vertical",
                          ticks=np.linspace(vmin, vmax, 4))
        cb.set_label("Density (g/cc$^3$)")

        ax = plt.subplot(212)
        mesh.plotSlice(
            L2out,
            ax=ax,
            normal="Y",
            ind=yslice,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.title("Cross Section")
        plt.xlabel("Easting(m)")
        plt.ylabel("Elevation")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(
            dat1[0],
            orientation="vertical",
            ticks=np.linspace(vmin, vmax, 4),
            cmap="bwr",
        )
        cb.set_label("Density (g/cc$^3$)")

        # %%
        # Make plots of Lp model
        yslice = midx + 1
        Lpout[Lpout == -100] = np.nan  # set "air" to nan

        plt.figure(figsize=(10, 7))
        plt.suptitle("Compact Inversion: Depth weight = " + str(wgtexp) +
                     ": $\epsilon_p$ = " + str(round(reg.eps_p, 1)) +
                     ": $\epsilon_q$ = " + str(round(reg.eps_q, 2)))
        ax = plt.subplot(221)
        dat = mesh.plotSlice(
            Lpout,
            ax=ax,
            normal="Z",
            ind=-16,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.plot(
            np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]),
            c="gray",
            linestyle="--",
        )
        plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color="k", s=1)
        plt.title("Z: " + str(mesh.vectorCCz[-16]) + " m")
        plt.xlabel("Easting (m)")
        plt.ylabel("Northing (m)")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(dat[0],
                          orientation="vertical",
                          ticks=np.linspace(vmin, vmax, 4))
        cb.set_label("Density (g/cc$^3$)")

        ax = plt.subplot(222)
        dat = mesh.plotSlice(
            Lpout,
            ax=ax,
            normal="Z",
            ind=-27,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.plot(
            np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]),
            np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]),
            c="gray",
            linestyle="--",
        )
        plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color="k", s=1)
        plt.title("Z: " + str(mesh.vectorCCz[-27]) + " m")
        plt.xlabel("Easting (m)")
        plt.ylabel("Northing (m)")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(dat[0],
                          orientation="vertical",
                          ticks=np.linspace(vmin, vmax, 4))
        cb.set_label("Density (g/cc$^3$)")

        ax = plt.subplot(212)
        dat = mesh.plotSlice(
            Lpout,
            ax=ax,
            normal="Y",
            ind=yslice,
            clim=(vmin, vmax),
            pcolorOpts={"cmap": "bwr"},
        )
        plt.title("Cross Section")
        plt.xlabel("Easting (m)")
        plt.ylabel("Elevation (m)")
        plt.gca().set_aspect("equal", adjustable="box")
        cb = plt.colorbar(dat[0],
                          orientation="vertical",
                          ticks=np.linspace(vmin, vmax, 4))
        cb.set_label("Density (g/cc$^3$)")
    def setUp(self):
        # We will assume a vertical inducing field
        H0 = (50000.0, 90.0, 0.0)

        # The magnetization is set along a different direction (induced + remanence)
        M = np.array([45.0, 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.0 + (yy / b)**2.0))
        topo = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)]

        # Create an 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)) + 10

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

        ###############################################################################
        # Inversion Mesh

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

        mesh = mesh_builder_xyz(rxLoc,
                                h,
                                padding_distance=padDist,
                                depth_core=100,
                                mesh_type="tree")
        mesh = refine_tree_xyz(mesh,
                               topo,
                               method="surface",
                               octree_levels=[4, 4],
                               finalize=True)

        # 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.mat_utils.dip_azimuth2cartesian(
            np.ones(nC) * M[0],
            np.ones(nC) * 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 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
        model = model[actv]

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

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

        # Compute some data and add some random noise
        synthetic_data = simulation.dpred(model)

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

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

        # Assigne data and uncertainties to the survey
        data_object = data.Data(survey, dobs=synthetic_data, noise_floor=wd)

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

        # Get the active cells for equivalent source is the top only
        surf = utils.model_utils.surface_layer_index(mesh, topo)
        nC = np.count_nonzero(surf)  # Number of active cells
        mstart = np.ones(nC) * 1e-4

        # 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
        simulation = magnetics.simulation.Simulation3DIntegral(
            mesh=mesh,
            survey=survey,
            chiMap=idenMap,
            actInd=surf,
            store_sensitivities="ram",
        )
        simulation.model = mstart

        # Create a regularization function, in this case l2l2
        reg = regularization.Sparse(mesh,
                                    indActive=surf,
                                    mapping=maps.IdentityMap(nP=nC),
                                    alpha_z=0)
        reg.mref = np.zeros(nC)

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

        # Define misfit function (obs-calc)
        dmis = data_misfit.L2DataMisfit(simulation=simulation,
                                        data=data_object)

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

        # Specify how the initial beta is found
        betaest = directives.BetaEstimate_ByEig(beta0_ratio=2)

        # 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,
                                      max_irls_iterations=5)
        update_Jacobi = directives.UpdatePreconditioner()
        # Put all the parts together
        inv = inversion.BaseInversion(
            invProb, directiveList=[betaest, IRLS, update_Jacobi])

        # Run the equivalent source inversion
        print("Solving for Equivalent Source")
        mrec = inv.run(mstart)

        ########################################################
        # Forward Amplitude Data
        # ----------------------
        #
        # Now that we have an equialent source layer, we can forward model alh three
        # components of the field and add them up: :math:`|B| = \sqrt{( Bx^2 + Bx^2 + Bx^2 )}`
        #

        rxList = magnetics.receivers.Point(rxLoc,
                                           components=["bx", "by", "bz"])
        srcField = magnetics.sources.SourceField(receiver_list=[rxList],
                                                 parameters=H0)
        surveyAmp = magnetics.survey.Survey(srcField)

        simulation = magnetics.simulation.Simulation3DIntegral(
            mesh=mesh,
            survey=surveyAmp,
            chiMap=idenMap,
            actInd=surf,
            is_amplitude_data=True,
            store_sensitivities="forward_only",
        )

        bAmp = simulation.fields(mrec)

        ######################################################################
        # Amplitude Inversion
        # -------------------
        #
        # Now that we have amplitude data, we can invert for an effective
        # susceptibility. This is a non-linear 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)

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

        # Create the forward model operator
        simulation = magnetics.simulation.Simulation3DIntegral(
            survey=surveyAmp,
            mesh=mesh,
            chiMap=idenMap,
            actInd=actv,
            is_amplitude_data=True,
        )

        data_obj = data.Data(survey, dobs=bAmp, noise_floor=wd)

        # Create a sparse regularization
        reg = regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
        reg.norms = np.c_[1, 0, 0, 0]
        reg.mref = np.zeros(nC)

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

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

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

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

        # Specify the sparse norms
        IRLS = directives.Update_IRLS(
            max_irls_iterations=5,
            f_min_change=1e-3,
            minGNiter=1,
            coolingRate=1,
            beta_search=False,
        )

        # Special directive specific to the mag amplitude problem. 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=[update_SensWeight, betaest, IRLS, update_Jacobi])

        self.mstart = mstart
        self.model = model
        self.sim = simulation
Exemple #16
0
# Here is the list of directives
betaest = directives.BetaEstimate_ByEig(beta0_ratio=1)

# Specify the sparse norms
IRLS = directives.Update_IRLS(
    max_irls_iterations=10,
    f_min_change=1e-3,
    minGNiter=1,
    coolingRate=1,
    beta_search=False,
)

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

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

# Invert
mrec_Amp = inv.run(mstart)

#############################################################
# Final Plot
# ----------
#
# Let's compare the smooth and compact model
# Note that the recovered effective susceptibility block is slightly offseted