예제 #1
0
    def setUpClass(self):

        print("\n------- Testing Primary Secondary Source EB -> EB --------\n")
        # receivers
        self.rxlist = []
        for rxtype in ["MagneticFluxDensity", "ElectricField"]:
            rx = getattr(fdem.Rx, "Point{}".format(rxtype))
            for orientation in ["x", "y", "z"]:
                for comp in ["real", "imag"]:
                    self.rxlist.append(
                        rx(rx_locs, component=comp, orientation=orientation))

        # primary
        self.primarySimulation = fdem.Simulation3DMagneticFluxDensity(
            meshp, sigmaMap=primaryMapping)
        self.primarySimulation.solver = Solver
        primarySrc = fdem.Src.MagDipole(self.rxlist,
                                        frequency=freq,
                                        location=src_loc)
        self.primarySurvey = fdem.Survey([primarySrc])

        self.secondarySrc = fdem.Src.PrimSecMappedSigma(
            self.rxlist,
            freq,
            self.primarySimulation,
            self.primarySurvey,
            primaryMap2Meshs,
        )
        self.secondarySurvey = fdem.Survey([self.secondarySrc])
        # Secondary Problem
        self.secondarySimulation = fdem.Simulation3DMagneticFluxDensity(
            meshs, survey=self.secondarySurvey, sigmaMap=mapping)
        self.secondarySimulation.solver = Solver

        # Full 3D problem to compare with
        self.survey3D = fdem.Survey([primarySrc])

        self.simulation3D = fdem.Simulation3DMagneticFluxDensity(
            meshs, survey=self.survey3D, sigmaMap=mapping)
        self.simulation3D.solver = Solver

        # solve and store fields
        print("   solving primary - secondary")
        self.fields_primsec = self.secondarySimulation.fields(model)
        print("     ... done")

        self.fields_primsec = self.secondarySimulation.fields(model)
        print("   solving 3D")
        self.fields_3D = self.simulation3D.fields(model)
        print("     ... done")

        return None
예제 #2
0
파일: Utils.py 프로젝트: emsig/oresd-amr
def define_survey(frequencies, receiver_locations, source_locations,
                  num_transmitters):
    """Defines a survey of a model with the receivers and the transmitters."""

    source_list = []
    for i in range(len(frequencies)):
        for j in range(num_transmitters):
            # Define receivers of different type at each location
            bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[j, :], "z", "real")
            bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[j, :], "z", "imag")
            receivers_list = [bzr_receiver, bzi_receiver]

            # Must define the transmitter properties and associated receivers
            source_list.append(
                fdem.sources.MagDipole(
                    receivers_list,
                    frequencies[i],
                    source_locations[j],
                    orientation="z",
                    moment=1,
                ))
    survey = fdem.Survey(source_list)
    return survey
예제 #3
0
    def setUp(self):
        print("\nTesting Transect for analytic")

        cs = 10.0
        ncx, ncy, ncz = 10, 10, 10
        npad = 5
        freq = 1e2

        hx = [(cs, npad, -1.3), (cs, ncx), (cs, npad, 1.3)]
        hy = [(cs, npad, -1.3), (cs, ncy), (cs, npad, 1.3)]
        hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)]
        mesh = discretize.TensorMesh([hx, hy, hz], "CCC")

        x = np.linspace(-10, 10, 5)
        XYZ = utils.ndgrid(x, np.r_[0], np.r_[0])
        rxList = fdem.Rx.PointElectricField(XYZ,
                                            orientation="x",
                                            component="imag")
        SrcList = [
            fdem.Src.MagDipole([rxList],
                               location=np.r_[0.0, 0.0, 0.0],
                               frequency=freq),
            fdem.Src.CircularLoop(
                [rxList],
                location=np.r_[0.0, 0.0, 0.0],
                frequency=freq,
                radius=np.sqrt(1.0 / np.pi),
            ),
            # fdem.Src.MagDipole_Bfield(
            #     [rxList], loc=np.r_[0., 0., 0.],
            #     freq=freq
            # ), # less accurate
        ]

        survey = fdem.Survey(SrcList)

        sig = 1e-1
        sigma = np.ones(mesh.nC) * sig
        sigma[mesh.gridCC[:, 2] > 0] = 1e-8

        prb = fdem.Simulation3DMagneticFluxDensity(mesh, sigma=sigma)
        prb.pair(survey)

        try:
            from pymatsolver import Pardiso

            prb.Solver = Pardiso
        except ImportError:
            prb.Solver = SolverLU

        self.prb = prb
        self.mesh = mesh
        self.sig = sig

        print(" starting solve ...")
        u = self.prb.fields()
        print(" ... done")
        self.u = u
예제 #4
0
    def setUpClass(self):

        print("\n------- Testing Primary Secondary Source HJ -> EB --------\n")
        # receivers
        self.rxlist = []
        for rxtype in ["MagneticFluxDensity", "ElectricField"]:
            rx = getattr(fdem.Rx, "Point{}".format(rxtype))
            for orientation in ["x", "y", "z"]:
                for comp in ["real", "imag"]:
                    self.rxlist.append(
                        rx(rx_locs, component=comp, orientation=orientation))

        # primary
        self.primarySimulation = fdem.Simulation3DCurrentDensity(
            meshp, sigmaMap=primaryMapping)
        self.primarySimulation.solver = Solver
        s_e = np.zeros(meshp.nF)
        inds = meshp.nFx + utils.closestPoints(meshp, src_loc, gridLoc="Fz")
        s_e[inds] = 1.0 / csz
        primarySrc = fdem.Src.RawVec_e(self.rxlist,
                                       freq=freq,
                                       s_e=s_e / meshp.area)
        self.primarySurvey = fdem.Survey([primarySrc])

        # Secondary Problem
        self.secondarySimulation = fdem.Simulation3DElectricField(
            meshs, sigmaMap=mapping)
        self.secondarySimulation.Solver = Solver
        self.secondarySrc = fdem.Src.PrimSecMappedSigma(
            self.rxlist,
            freq,
            self.primarySimulation,
            self.primarySurvey,
            primaryMap2Meshs,
        )
        self.secondarySurvey = fdem.Survey([self.secondarySrc])
        self.secondarySimulation.pair(self.secondarySurvey)

        # Full 3D problem to compare with
        self.simulation3D = fdem.Simulation3DElectricField(meshs,
                                                           sigmaMap=mapping)
        self.simulation3D.Solver = Solver
        s_e3D = np.zeros(meshs.nE)
        inds = meshs.nEx + meshs.nEy + utils.closestPoints(
            meshs, src_loc, gridLoc="Ez")
        s_e3D[inds] = [1.0 / (len(inds))] * len(inds)
        self.simulation3D.model = model
        src3D = fdem.Src.RawVec_e(self.rxlist, freq=freq, s_e=s_e3D)
        self.survey3D = fdem.Survey([src3D])
        self.simulation3D.pair(self.survey3D)

        # solve and store fields
        print("   solving primary - secondary")
        self.fields_primsec = self.secondarySimulation.fields(model)
        print("     ... done")

        self.fields_primsec = self.secondarySimulation.fields(model)
        print("   solving 3D")
        self.fields_3D = self.simulation3D.fields(model)
        print("     ... done")

        return None
def resolve_1Dinversions(
    mesh,
    dobs,
    src_height,
    freqs,
    m0,
    mref,
    mapping,
    relative=0.08,
    floor=1e-14,
    rxOffset=7.86,
):
    """
    Perform a single 1D inversion for a RESOLVE sounding for Horizontal
    Coplanar Coil data (both real and imaginary).

    :param discretize.CylMesh mesh: mesh used for the forward simulation
    :param numpy.ndarray dobs: observed data
    :param float src_height: height of the source above the ground
    :param numpy.ndarray freqs: frequencies
    :param numpy.ndarray m0: starting model
    :param numpy.ndarray mref: reference model
    :param maps.IdentityMap mapping: mapping that maps the model to electrical conductivity
    :param float relative: percent error used to construct the data misfit term
    :param float floor: noise floor used to construct the data misfit term
    :param float rxOffset: offset between source and receiver.
    """

    # ------------------- Forward Simulation ------------------- #
    # set up the receivers
    bzr = FDEM.Rx.PointMagneticFluxDensitySecondary(np.array(
        [[rxOffset, 0.0, src_height]]),
                                                    orientation="z",
                                                    component="real")

    bzi = FDEM.Rx.PointMagneticFluxDensity(np.array(
        [[rxOffset, 0.0, src_height]]),
                                           orientation="z",
                                           component="imag")

    # source location
    srcLoc = np.array([0.0, 0.0, src_height])
    srcList = [
        FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z")
        for freq in freqs
    ]

    # construct a forward simulation
    survey = FDEM.Survey(srcList)
    prb = FDEM.Simulation3DMagneticFluxDensity(mesh,
                                               sigmaMap=mapping,
                                               Solver=PardisoSolver)
    prb.survey = survey

    # ------------------- Inversion ------------------- #
    # data misfit term
    uncert = abs(dobs) * relative + floor
    dat = data.Data(dobs=dobs, standard_deviation=uncert)
    dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=dat)

    # regularization
    regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
    reg = regularization.Simple(regMesh)
    reg.mref = mref

    # optimization
    opt = optimization.InexactGaussNewton(maxIter=10)

    # statement of the inverse problem
    invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)

    # Inversion directives and parameters
    target = directives.TargetMisfit()
    inv = inversion.BaseInversion(invProb, directiveList=[target])

    invProb.beta = 2.0  # Fix beta in the nonlinear iterations
    reg.alpha_s = 1e-3
    reg.alpha_x = 1.0
    prb.counter = opt.counter = utils.Counter()
    opt.LSshorten = 0.5
    opt.remember("xc")

    # run the inversion
    mopt = inv.run(m0)
    return mopt, invProb.dpred, survey.dobs
def run(plotIt=True, saveFig=False):

    # Set up cylindrically symmeric mesh
    cs, ncx, ncz, npad = 10.0, 15, 25, 13  # padded cyl mesh
    hx = [(cs, ncx), (cs, npad, 1.3)]
    hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)]
    mesh = discretize.CylMesh([hx, 1, hz], "00C")

    # Conductivity model
    layerz = np.r_[-200.0, -100.0]
    layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1])
    active = mesh.vectorCCz < 0.0
    sig_half = 1e-2  # Half-space conductivity
    sig_air = 1e-8  # Air conductivity
    sig_layer = 5e-2  # Layer conductivity
    sigma = np.ones(mesh.nCz) * sig_air
    sigma[active] = sig_half
    sigma[layer] = sig_layer

    # Mapping
    actMap = maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz)
    mapping = maps.ExpMap(mesh) * maps.SurjectVertical1D(mesh) * actMap
    mtrue = np.log(sigma[active])

    # ----- FDEM problem & survey ----- #
    rxlocs = utils.ndgrid([np.r_[50.0], np.r_[0], np.r_[0.0]])
    bzr = FDEM.Rx.PointMagneticFluxDensitySecondary(rxlocs, "z", "real")
    bzi = FDEM.Rx.PointMagneticFluxDensitySecondary(rxlocs, "z", "imag")

    freqs = np.logspace(2, 3, 5)
    srcLoc = np.array([0.0, 0.0, 0.0])

    print(
        "min skin depth = ",
        500.0 / np.sqrt(freqs.max() * sig_half),
        "max skin depth = ",
        500.0 / np.sqrt(freqs.min() * sig_half),
    )
    print(
        "max x ",
        mesh.vectorCCx.max(),
        "min z ",
        mesh.vectorCCz.min(),
        "max z ",
        mesh.vectorCCz.max(),
    )

    source_list = [
        FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z") for freq in freqs
    ]

    surveyFD = FDEM.Survey(source_list)
    prbFD = FDEM.Simulation3DMagneticFluxDensity(
        mesh, survey=surveyFD, sigmaMap=mapping, solver=Solver
    )
    rel_err = 0.03
    dataFD = prbFD.make_synthetic_data(mtrue, relative_error=rel_err, add_noise=True)
    dataFD.noise_floor = np.linalg.norm(dataFD.dclean) * 1e-5

    # FDEM inversion
    np.random.seed(1)
    dmisfit = data_misfit.L2DataMisfit(simulation=prbFD, data=dataFD)
    regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
    reg = regularization.Simple(regMesh)
    opt = optimization.InexactGaussNewton(maxIterCG=10)
    invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)

    # Inversion Directives
    beta = directives.BetaSchedule(coolingFactor=4, coolingRate=3)
    betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, seed=518936)
    target = directives.TargetMisfit()
    directiveList = [beta, betaest, target]

    inv = inversion.BaseInversion(invProb, directiveList=directiveList)
    m0 = np.log(np.ones(mtrue.size) * sig_half)
    reg.alpha_s = 5e-1
    reg.alpha_x = 1.0
    prbFD.counter = opt.counter = utils.Counter()
    opt.remember("xc")
    moptFD = inv.run(m0)

    # TDEM problem
    times = np.logspace(-4, np.log10(2e-3), 10)
    print(
        "min diffusion distance ",
        1.28 * np.sqrt(times.min() / (sig_half * mu_0)),
        "max diffusion distance ",
        1.28 * np.sqrt(times.max() / (sig_half * mu_0)),
    )
    rx = TDEM.Rx.PointMagneticFluxDensity(rxlocs, times, "z")
    src = TDEM.Src.MagDipole(
        [rx],
        waveform=TDEM.Src.StepOffWaveform(),
        location=srcLoc,  # same src location as FDEM problem
    )

    surveyTD = TDEM.Survey([src])
    prbTD = TDEM.Simulation3DMagneticFluxDensity(
        mesh, survey=surveyTD, sigmaMap=mapping, solver=Solver
    )
    prbTD.time_steps = [(5e-5, 10), (1e-4, 10), (5e-4, 10)]

    rel_err = 0.03
    dataTD = prbTD.make_synthetic_data(mtrue, relative_error=rel_err, add_noise=True)
    dataTD.noise_floor = np.linalg.norm(dataTD.dclean) * 1e-5

    # TDEM inversion
    dmisfit = data_misfit.L2DataMisfit(simulation=prbTD, data=dataTD)
    regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
    reg = regularization.Simple(regMesh)
    opt = optimization.InexactGaussNewton(maxIterCG=10)
    invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)

    # directives
    beta = directives.BetaSchedule(coolingFactor=4, coolingRate=3)
    betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, seed=518936)
    target = directives.TargetMisfit()
    directiveList = [beta, betaest, target]

    inv = inversion.BaseInversion(invProb, directiveList=directiveList)
    m0 = np.log(np.ones(mtrue.size) * sig_half)
    reg.alpha_s = 5e-1
    reg.alpha_x = 1.0
    prbTD.counter = opt.counter = utils.Counter()
    opt.remember("xc")
    moptTD = inv.run(m0)

    # Plot the results
    if plotIt:
        plt.figure(figsize=(10, 8))
        ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2)
        ax1 = plt.subplot2grid((2, 2), (0, 1))
        ax2 = plt.subplot2grid((2, 2), (1, 1))

        fs = 13  # fontsize
        matplotlib.rcParams["font.size"] = fs

        # Plot the model
        # z_true = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0)
        # z_true = np.r_[mesh.vectorCCz[active][0], z_true, mesh.vectorCCz[active][-1]]
        activeN = mesh.vectorNz <= 0.0 + cs / 2.0
        z_true = np.repeat(mesh.vectorNz[activeN][1:-1], 2, axis=0)
        z_true = np.r_[mesh.vectorNz[activeN][0], z_true, mesh.vectorNz[activeN][-1]]
        sigma_true = np.repeat(sigma[active], 2, axis=0)

        ax0.semilogx(sigma_true, z_true, "k-", lw=2, label="True")

        ax0.semilogx(
            np.exp(moptFD),
            mesh.vectorCCz[active],
            "bo",
            ms=6,
            markeredgecolor="k",
            markeredgewidth=0.5,
            label="FDEM",
        )
        ax0.semilogx(
            np.exp(moptTD),
            mesh.vectorCCz[active],
            "r*",
            ms=10,
            markeredgecolor="k",
            markeredgewidth=0.5,
            label="TDEM",
        )
        ax0.set_ylim(-700, 0)
        ax0.set_xlim(5e-3, 1e-1)

        ax0.set_xlabel("Conductivity (S/m)", fontsize=fs)
        ax0.set_ylabel("Depth (m)", fontsize=fs)
        ax0.grid(which="both", color="k", alpha=0.5, linestyle="-", linewidth=0.2)
        ax0.legend(fontsize=fs, loc=4)

        # plot the data misfits - negative b/c we choose positive to be in the
        # direction of primary

        ax1.plot(freqs, -dataFD.dobs[::2], "k-", lw=2, label="Obs (real)")
        ax1.plot(freqs, -dataFD.dobs[1::2], "k--", lw=2, label="Obs (imag)")

        dpredFD = prbFD.dpred(moptTD)
        ax1.loglog(
            freqs,
            -dpredFD[::2],
            "bo",
            ms=6,
            markeredgecolor="k",
            markeredgewidth=0.5,
            label="Pred (real)",
        )
        ax1.loglog(
            freqs, -dpredFD[1::2], "b+", ms=10, markeredgewidth=2.0, label="Pred (imag)"
        )

        ax2.loglog(times, dataTD.dobs, "k-", lw=2, label="Obs")
        ax2.loglog(
            times,
            prbTD.dpred(moptTD),
            "r*",
            ms=10,
            markeredgecolor="k",
            markeredgewidth=0.5,
            label="Pred",
        )
        ax2.set_xlim(times.min() - 1e-5, times.max() + 1e-4)

        # Labels, gridlines, etc
        ax2.grid(which="both", alpha=0.5, linestyle="-", linewidth=0.2)
        ax1.grid(which="both", alpha=0.5, linestyle="-", linewidth=0.2)

        ax1.set_xlabel("Frequency (Hz)", fontsize=fs)
        ax1.set_ylabel("Vertical magnetic field (-T)", fontsize=fs)

        ax2.set_xlabel("Time (s)", fontsize=fs)
        ax2.set_ylabel("Vertical magnetic field (T)", fontsize=fs)

        ax2.legend(fontsize=fs, loc=3)
        ax1.legend(fontsize=fs, loc=3)
        ax1.set_xlim(freqs.max() + 1e2, freqs.min() - 1e1)

        ax0.set_title("(a) Recovered Models", fontsize=fs)
        ax1.set_title("(b) FDEM observed vs. predicted", fontsize=fs)
        ax2.set_title("(c) TDEM observed vs. predicted", fontsize=fs)

        plt.tight_layout(pad=1.5)

        if saveFig is True:
            plt.savefig("example1.png", dpi=600)
def run(plotIt=True):

    # ------------------ MODEL ------------------
    sigmaair = 1e-8  # air
    sigmaback = 1e-2  # background
    sigmacasing = 1e6  # casing
    sigmainside = sigmaback  # inside the casing

    casing_t = 0.006  # 1cm thickness
    casing_l = 300  # length of the casing

    casing_r = 0.1
    casing_a = casing_r - casing_t / 2.0  # inner radius
    casing_b = casing_r + casing_t / 2.0  # outer radius
    casing_z = np.r_[-casing_l, 0.0]

    # ------------------ SURVEY PARAMETERS ------------------
    freqs = np.r_[1e-6]  # [1e-1, 1, 5] # frequencies
    dsz = -300  # down-hole z source location
    src_loc = np.r_[0.0, 0.0, dsz]
    inf_loc = np.r_[0.0, 0.0, 1e4]

    print("Skin Depth: ", [(500.0 / np.sqrt(sigmaback * _)) for _ in freqs])

    # ------------------ MESH ------------------
    # fine cells near well bore
    csx1, csx2 = 2e-3, 60.0
    pfx1, pfx2 = 1.3, 1.3
    ncx1 = np.ceil(casing_b / csx1 + 2)

    # pad nicely to second cell size
    npadx1 = np.floor(np.log(csx2 / csx1) / np.log(pfx1))
    hx1a = utils.meshTensor([(csx1, ncx1)])
    hx1b = utils.meshTensor([(csx1, npadx1, pfx1)])
    dx1 = sum(hx1a) + sum(hx1b)
    dx1 = np.floor(dx1 / csx2)
    hx1b *= (dx1 * csx2 - sum(hx1a)) / sum(hx1b)

    # second chunk of mesh
    dx2 = 300.0  # uniform mesh out to here
    ncx2 = np.ceil((dx2 - dx1) / csx2)
    npadx2 = 45
    hx2a = utils.meshTensor([(csx2, ncx2)])
    hx2b = utils.meshTensor([(csx2, npadx2, pfx2)])
    hx = np.hstack([hx1a, hx1b, hx2a, hx2b])

    # z-direction
    csz = 0.05
    nza = 10
    # cell size, number of core cells, number of padding cells in the
    # x-direction
    ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0] / csz)) + 10, 68, 68
    # vector of cell widths in the z-direction
    hz = utils.meshTensor([(csz, npadzd, -1.3), (csz, ncz), (csz, npadzu, 1.3)])

    # Mesh
    mesh = discretize.CylMesh(
        [hx, 1.0, hz], [0.0, 0.0, -np.sum(hz[: npadzu + ncz - nza])]
    )

    print(
        "Mesh Extent xmax: {0:f},: zmin: {1:f}, zmax: {2:f}".format(
            mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max()
        )
    )
    print("Number of cells", mesh.nC)

    if plotIt is True:
        fig, ax = plt.subplots(1, 1, figsize=(6, 4))
        ax.set_title("Simulation Mesh")
        mesh.plotGrid(ax=ax)

    # Put the model on the mesh
    sigWholespace = sigmaback * np.ones((mesh.nC))

    sigBack = sigWholespace.copy()
    sigBack[mesh.gridCC[:, 2] > 0.0] = sigmaair

    sigCasing = sigBack.copy()
    iCasingZ = (mesh.gridCC[:, 2] <= casing_z[1]) & (mesh.gridCC[:, 2] >= casing_z[0])
    iCasingX = (mesh.gridCC[:, 0] >= casing_a) & (mesh.gridCC[:, 0] <= casing_b)
    iCasing = iCasingX & iCasingZ
    sigCasing[iCasing] = sigmacasing

    if plotIt is True:
        # plotting parameters
        xlim = np.r_[0.0, 0.2]
        zlim = np.r_[-350.0, 10.0]
        clim_sig = np.r_[-8, 6]

        # plot models
        fig, ax = plt.subplots(1, 1, figsize=(4, 4))

        im = mesh.plotImage(np.log10(sigCasing), ax=ax)[0]
        im.set_clim(clim_sig)
        plt.colorbar(im, ax=ax)
        ax.grid(which="both")
        ax.set_title("Log_10 (Sigma)")
        ax.set_xlim(xlim)
        ax.set_ylim(zlim)

    # -------------- Sources --------------------
    # Define Custom Current Sources

    # surface source
    sg_x = np.zeros(mesh.vnF[0], dtype=complex)
    sg_y = np.zeros(mesh.vnF[1], dtype=complex)
    sg_z = np.zeros(mesh.vnF[2], dtype=complex)

    nza = 2  # put the wire two cells above the surface

    # vertically directed wire
    # hook it up to casing at the surface
    sgv_indx = (mesh.gridFz[:, 0] > casing_a) & (mesh.gridFz[:, 0] < casing_a + csx1)
    sgv_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] >= -csz * 2)
    sgv_ind = sgv_indx & sgv_indz
    sg_z[sgv_ind] = -1.0

    # horizontally directed wire
    sgh_indx = (mesh.gridFx[:, 0] > casing_a) & (mesh.gridFx[:, 0] <= inf_loc[2])
    sgh_indz = (mesh.gridFx[:, 2] > csz * (nza - 0.5)) & (
        mesh.gridFx[:, 2] < csz * (nza + 0.5)
    )
    sgh_ind = sgh_indx & sgh_indz
    sg_x[sgh_ind] = -1.0

    # hook it up to casing at the surface
    sgv2_indx = (mesh.gridFz[:, 0] >= mesh.gridFx[sgh_ind, 0].max()) & (
        mesh.gridFz[:, 0] <= inf_loc[2] * 1.2
    )
    sgv2_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] >= -csz * 2)
    sgv2_ind = sgv2_indx & sgv2_indz
    sg_z[sgv2_ind] = 1.0

    # assemble the source
    sg = np.hstack([sg_x, sg_y, sg_z])
    sg_p = [FDEM.Src.RawVec_e([], _, sg / mesh.area) for _ in freqs]

    # downhole source
    dg_x = np.zeros(mesh.vnF[0], dtype=complex)
    dg_y = np.zeros(mesh.vnF[1], dtype=complex)
    dg_z = np.zeros(mesh.vnF[2], dtype=complex)

    # vertically directed wire
    dgv_indx = mesh.gridFz[:, 0] < csx1  # go through the center of the well
    dgv_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] > dsz + csz / 2.0)
    dgv_ind = dgv_indx & dgv_indz
    dg_z[dgv_ind] = -1.0

    # couple to the casing downhole
    dgh_indx = mesh.gridFx[:, 0] < casing_a + csx1
    dgh_indz = (mesh.gridFx[:, 2] < dsz + csz) & (mesh.gridFx[:, 2] >= dsz)
    dgh_ind = dgh_indx & dgh_indz
    dg_x[dgh_ind] = 1.0

    # horizontal part at surface
    dgh2_indx = mesh.gridFx[:, 0] <= inf_loc[2] * 1.2
    dgh2_indz = sgh_indz.copy()
    dgh2_ind = dgh2_indx & dgh2_indz
    dg_x[dgh2_ind] = -1.0

    # vertical part at surface
    dgv2_ind = sgv2_ind.copy()
    dg_z[dgv2_ind] = 1.0

    # assemble the source
    dg = np.hstack([dg_x, dg_y, dg_z])
    dg_p = [FDEM.Src.RawVec_e([], _, dg / mesh.area) for _ in freqs]

    # ------------ Problem and Survey ---------------
    survey = FDEM.Survey(sg_p + dg_p)
    problem = FDEM.Simulation3DMagneticField(
        mesh, survey=survey, sigmaMap=maps.IdentityMap(mesh), solver=Solver
    )

    # ------------- Solve ---------------------------
    t0 = time.time()
    fieldsCasing = problem.fields(sigCasing)
    print("Time to solve 2 sources", time.time() - t0)

    # Plot current

    # current density
    jn0 = fieldsCasing[dg_p, "j"]
    jn1 = fieldsCasing[sg_p, "j"]

    # current
    in0 = [mesh.area * fieldsCasing[dg_p, "j"][:, i] for i in range(len(freqs))]
    in1 = [mesh.area * fieldsCasing[sg_p, "j"][:, i] for i in range(len(freqs))]

    in0 = np.vstack(in0).T
    in1 = np.vstack(in1).T

    # integrate to get z-current inside casing
    inds_inx = (mesh.gridFz[:, 0] >= casing_a) & (mesh.gridFz[:, 0] <= casing_b)
    inds_inz = (mesh.gridFz[:, 2] >= dsz) & (mesh.gridFz[:, 2] <= 0)
    inds_fz = inds_inx & inds_inz

    indsx = [False] * mesh.nFx
    inds = list(indsx) + list(inds_fz)

    in0_in = in0[np.r_[inds]]
    in1_in = in1[np.r_[inds]]
    z_in = mesh.gridFz[inds_fz, 2]

    in0_in = in0_in.reshape([in0_in.shape[0] // 3, 3])
    in1_in = in1_in.reshape([in1_in.shape[0] // 3, 3])
    z_in = z_in.reshape([z_in.shape[0] // 3, 3])

    I0 = in0_in.sum(1).real
    I1 = in1_in.sum(1).real
    z_in = z_in[:, 0]

    if plotIt is True:
        fig, ax = plt.subplots(1, 2, figsize=(12, 4))

        ax[0].plot(z_in, np.absolute(I0), z_in, np.absolute(I1))
        ax[0].legend(["top casing", "bottom casing"], loc="best")
        ax[0].set_title("Magnitude of Vertical Current in Casing")

        ax[1].semilogy(z_in, np.absolute(I0), z_in, np.absolute(I1))
        ax[1].legend(["top casing", "bottom casing"], loc="best")
        ax[1].set_title("Magnitude of Vertical Current in Casing")
        ax[1].set_ylim([1e-2, 1.0])
예제 #8
0
    def test_CylMeshEBDipoles(self, plotIt=plotIt):
        print("Testing CylMesh Electric and Magnetic Dipoles in a wholespace-"
              " Analytic: J-formulation")
        sigmaback = 1.0
        mur = 2.0
        freq = 1.0
        skdpth = 500.0 / np.sqrt(sigmaback * freq)

        csx, ncx, npadx = 5, 50, 25
        csz, ncz, npadz = 5, 50, 25

        hx = utils.meshTensor([(csx, ncx), (csx, npadx, 1.3)])
        hz = utils.meshTensor([(csz, npadz, -1.3), (csz, ncz),
                               (csz, npadz, 1.3)])

        # define the cylindrical mesh
        mesh = discretize.CylMesh([hx, 1, hz], [0.0, 0.0, -hz.sum() / 2])

        if plotIt:
            mesh.plotGrid()

        # make sure mesh is big enough
        self.assertTrue(mesh.hz.sum() > skdpth * 2.0)
        self.assertTrue(mesh.hx.sum() > skdpth * 2.0)

        # set up source
        # test electric dipole
        src_loc = np.r_[0.0, 0.0, 0.0]
        s_ind = utils.closestPoints(mesh, src_loc, "Fz") + mesh.nFx

        de = np.zeros(mesh.nF, dtype=complex)
        de[s_ind] = 1.0 / csz
        de_p = [fdem.Src.RawVec_e([], freq, de / mesh.area)]

        dm_p = [fdem.Src.MagDipole([], freq, src_loc)]

        # Pair the problem and survey
        surveye = fdem.Survey(de_p)
        surveym = fdem.Survey(dm_p)

        prbe = fdem.Simulation3DMagneticField(mesh,
                                              survey=surveye,
                                              sigma=sigmaback,
                                              mu=mur * mu_0)
        prbm = fdem.Simulation3DElectricField(mesh,
                                              survey=surveym,
                                              sigma=sigmaback,
                                              mu=mur * mu_0)

        # solve
        fieldsBackE = prbe.fields()
        fieldsBackM = prbm.fields()

        rlim = [20.0, 500.0]
        # lookAtTx = de_p
        r = mesh.vectorCCx[np.argmin(np.abs(mesh.vectorCCx - rlim[0])):np.
                           argmin(np.abs(mesh.vectorCCx - rlim[1]))]
        z = 100.0

        # where we choose to measure
        XYZ = utils.ndgrid(r, np.r_[0.0], np.r_[z])

        Pf = mesh.getInterpolationMat(XYZ, "CC")
        Zero = sp.csr_matrix(Pf.shape)
        Pfx, Pfz = sp.hstack([Pf, Zero]), sp.hstack([Zero, Pf])

        jn = fieldsBackE[de_p, "j"]
        bn = fieldsBackM[dm_p, "b"]

        SigmaBack = sigmaback * np.ones((mesh.nC))
        Rho = utils.sdiag(1.0 / SigmaBack)
        Rho = sp.block_diag([Rho, Rho])

        en = Rho * mesh.aveF2CCV * jn
        bn = mesh.aveF2CCV * bn

        ex, ez = Pfx * en, Pfz * en
        bx, bz = Pfx * bn, Pfz * bn

        # get analytic solution
        exa, eya, eza = analytics.FDEM.ElectricDipoleWholeSpace(XYZ,
                                                                src_loc,
                                                                sigmaback,
                                                                freq,
                                                                "Z",
                                                                mu_r=mur)

        exa = utils.mkvc(exa, 2)
        eya = utils.mkvc(eya, 2)
        eza = utils.mkvc(eza, 2)

        bxa, bya, bza = analytics.FDEM.MagneticDipoleWholeSpace(XYZ,
                                                                src_loc,
                                                                sigmaback,
                                                                freq,
                                                                "Z",
                                                                mu_r=mur)
        bxa = utils.mkvc(bxa, 2)
        bya = utils.mkvc(bya, 2)
        bza = utils.mkvc(bza, 2)

        print(
            " comp,       anayltic,       numeric,       num - ana,       (num - ana)/ana"
        )
        print(
            "  ex:",
            np.linalg.norm(exa),
            np.linalg.norm(ex),
            np.linalg.norm(exa - ex),
            np.linalg.norm(exa - ex) / np.linalg.norm(exa),
        )
        print(
            "  ez:",
            np.linalg.norm(eza),
            np.linalg.norm(ez),
            np.linalg.norm(eza - ez),
            np.linalg.norm(eza - ez) / np.linalg.norm(eza),
        )

        print(
            "  bx:",
            np.linalg.norm(bxa),
            np.linalg.norm(bx),
            np.linalg.norm(bxa - bx),
            np.linalg.norm(bxa - bx) / np.linalg.norm(bxa),
        )
        print(
            "  bz:",
            np.linalg.norm(bza),
            np.linalg.norm(bz),
            np.linalg.norm(bza - bz),
            np.linalg.norm(bza - bz) / np.linalg.norm(bza),
        )

        if plotIt is True:
            # Edipole
            plt.subplot(221)
            plt.plot(r, ex.real, "o", r, exa.real, linewidth=2)
            plt.grid(which="both")
            plt.title("Ex Real")
            plt.xlabel("r (m)")

            plt.subplot(222)
            plt.plot(r, ex.imag, "o", r, exa.imag, linewidth=2)
            plt.grid(which="both")
            plt.title("Ex Imag")
            plt.legend(["Num", "Ana"], bbox_to_anchor=(1.5, 0.5))
            plt.xlabel("r (m)")

            plt.subplot(223)
            plt.plot(r, ez.real, "o", r, eza.real, linewidth=2)
            plt.grid(which="both")
            plt.title("Ez Real")
            plt.xlabel("r (m)")

            plt.subplot(224)
            plt.plot(r, ez.imag, "o", r, eza.imag, linewidth=2)
            plt.grid(which="both")
            plt.title("Ez Imag")
            plt.xlabel("r (m)")

            plt.tight_layout()

            # Bdipole
            plt.subplot(221)
            plt.plot(r, bx.real, "o", r, bxa.real, linewidth=2)
            plt.grid(which="both")
            plt.title("Bx Real")
            plt.xlabel("r (m)")

            plt.subplot(222)
            plt.plot(r, bx.imag, "o", r, bxa.imag, linewidth=2)
            plt.grid(which="both")
            plt.title("Bx Imag")
            plt.legend(["Num", "Ana"], bbox_to_anchor=(1.5, 0.5))
            plt.xlabel("r (m)")

            plt.subplot(223)
            plt.plot(r, bz.real, "o", r, bza.real, linewidth=2)
            plt.grid(which="both")
            plt.title("Bz Real")
            plt.xlabel("r (m)")

            plt.subplot(224)
            plt.plot(r, bz.imag, "o", r, bza.imag, linewidth=2)
            plt.grid(which="both")
            plt.title("Bz Imag")
            plt.xlabel("r (m)")

            plt.tight_layout()

        self.assertTrue(
            np.linalg.norm(exa - ex) / np.linalg.norm(exa) < tol_EBdipole)
        self.assertTrue(
            np.linalg.norm(eza - ez) / np.linalg.norm(eza) < tol_EBdipole)

        self.assertTrue(
            np.linalg.norm(bxa - bx) / np.linalg.norm(bxa) < tol_EBdipole)
        self.assertTrue(
            np.linalg.norm(bza - bz) / np.linalg.norm(bza) < tol_EBdipole)
예제 #9
0
def run(plotIt=True, saveFig=False, cleanup=True):
    """
    Run 1D inversions for a single sounding of the RESOLVE and SkyTEM
    bookpurnong data

    :param bool plotIt: show the plots?
    :param bool saveFig: save the figure
    :param bool cleanup: remove the downloaded results
    """
    downloads, directory = download_and_unzip_data()

    resolve = h5py.File(os.path.sep.join([directory, "booky_resolve.hdf5"]),
                        "r")
    skytem = h5py.File(os.path.sep.join([directory, "booky_skytem.hdf5"]), "r")
    river_path = resolve["river_path"].value

    # Choose a sounding location to invert
    xloc, yloc = 462100.0, 6196500.0
    rxind_skytem = np.argmin(
        abs(skytem["xy"][:, 0] - xloc) + abs(skytem["xy"][:, 1] - yloc))
    rxind_resolve = np.argmin(
        abs(resolve["xy"][:, 0] - xloc) + abs(resolve["xy"][:, 1] - yloc))

    # Plot both resolve and skytem data on 2D plane
    fig = plt.figure(figsize=(13, 6))
    title = ["RESOLVE In-phase 400 Hz", "SkyTEM High moment 156 $\mu$s"]
    ax1 = plt.subplot(121)
    ax2 = plt.subplot(122)
    axs = [ax1, ax2]
    out_re = utils.plot2Ddata(
        resolve["xy"],
        resolve["data"][:, 0],
        ncontour=100,
        contourOpts={"cmap": "viridis"},
        ax=ax1,
    )
    vmin, vmax = out_re[0].get_clim()
    cb_re = plt.colorbar(out_re[0],
                         ticks=np.linspace(vmin, vmax, 3),
                         ax=ax1,
                         fraction=0.046,
                         pad=0.04)
    temp_skytem = skytem["data"][:, 5].copy()
    temp_skytem[skytem["data"][:, 5] > 7e-10] = 7e-10
    out_sky = utils.plot2Ddata(
        skytem["xy"][:, :2],
        temp_skytem,
        ncontour=100,
        contourOpts={
            "cmap": "viridis",
            "vmax": 7e-10
        },
        ax=ax2,
    )
    vmin, vmax = out_sky[0].get_clim()
    cb_sky = plt.colorbar(
        out_sky[0],
        ticks=np.linspace(vmin, vmax * 0.99, 3),
        ax=ax2,
        format="%.1e",
        fraction=0.046,
        pad=0.04,
    )
    cb_re.set_label("Bz (ppm)")
    cb_sky.set_label("dB$_z$ / dt (V/A-m$^4$)")

    for i, ax in enumerate(axs):
        xticks = [460000, 463000]
        yticks = [6195000, 6198000, 6201000]
        ax.set_xticks(xticks)
        ax.set_yticks(yticks)
        ax.plot(xloc, yloc, "wo")
        ax.plot(river_path[:, 0], river_path[:, 1], "k", lw=0.5)

        ax.set_aspect("equal")
        if i == 1:
            ax.plot(skytem["xy"][:, 0],
                    skytem["xy"][:, 1],
                    "k.",
                    alpha=0.02,
                    ms=1)
            ax.set_yticklabels([str(" ") for f in yticks])
        else:
            ax.plot(resolve["xy"][:, 0],
                    resolve["xy"][:, 1],
                    "k.",
                    alpha=0.02,
                    ms=1)
            ax.set_yticklabels([str(f) for f in yticks])
            ax.set_ylabel("Northing (m)")
        ax.set_xlabel("Easting (m)")
        ax.set_title(title[i])
        ax.axis("equal")
    # plt.tight_layout()

    if saveFig is True:
        fig.savefig("resolve_skytem_data.png", dpi=600)

    # ------------------ Mesh ------------------ #
    # Step1: Set 2D cylindrical mesh
    cs, ncx, ncz, npad = 1.0, 10.0, 10.0, 20
    hx = [(cs, ncx), (cs, npad, 1.3)]
    npad = 12
    temp = np.logspace(np.log10(1.0), np.log10(12.0), 19)
    temp_pad = temp[-1] * 1.3**np.arange(npad)
    hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad]
    mesh = discretize.CylMesh([hx, 1, hz], "00C")
    active = mesh.vectorCCz < 0.0

    # Step2: Set a SurjectVertical1D mapping
    # Note: this sets our inversion model as 1D log conductivity
    # below subsurface

    active = mesh.vectorCCz < 0.0
    actMap = maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz)
    mapping = maps.ExpMap(mesh) * maps.SurjectVertical1D(mesh) * actMap
    sig_half = 1e-1
    sig_air = 1e-8
    sigma = np.ones(mesh.nCz) * sig_air
    sigma[active] = sig_half

    # Initial and reference model
    m0 = np.log(sigma[active])

    # ------------------ RESOLVE Forward Simulation ------------------ #
    # Step3: Invert Resolve data

    # Bird height from the surface
    b_height_resolve = resolve["src_elevation"].value
    src_height_resolve = b_height_resolve[rxind_resolve]

    # Set Rx (In-phase and Quadrature)
    rxOffset = 7.86
    bzr = FDEM.Rx.PointMagneticFluxDensitySecondary(
        np.array([[rxOffset, 0.0, src_height_resolve]]),
        orientation="z",
        component="real",
    )

    bzi = FDEM.Rx.PointMagneticFluxDensity(
        np.array([[rxOffset, 0.0, src_height_resolve]]),
        orientation="z",
        component="imag",
    )

    # Set Source (In-phase and Quadrature)
    frequency_cp = resolve["frequency_cp"].value
    freqs = frequency_cp.copy()
    srcLoc = np.array([0.0, 0.0, src_height_resolve])
    srcList = [
        FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z")
        for freq in freqs
    ]

    # Set FDEM survey (In-phase and Quadrature)
    survey = FDEM.Survey(srcList)
    prb = FDEM.Simulation3DMagneticFluxDensity(mesh,
                                               sigmaMap=mapping,
                                               Solver=Solver)
    prb.survey = survey

    # ------------------ RESOLVE Inversion ------------------ #

    # Primary field
    bp = -mu_0 / (4 * np.pi * rxOffset**3)

    # Observed data
    cpi_inds = [0, 2, 6, 8, 10]
    cpq_inds = [1, 3, 7, 9, 11]
    dobs_re = (np.c_[resolve["data"][rxind_resolve, :][cpi_inds],
                     resolve["data"][rxind_resolve, :][cpq_inds], ].flatten() *
               bp * 1e-6)

    # Uncertainty
    relative = np.repeat(np.r_[np.ones(3) * 0.1, np.ones(2) * 0.15], 2)
    floor = 20 * abs(bp) * 1e-6
    std = abs(dobs_re) * relative + floor

    # Data Misfit
    data_resolve = data.Data(dobs=dobs_re,
                             survey=survey,
                             standard_deviation=std)
    dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data_resolve)

    # Regularization
    regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
    reg = regularization.Simple(regMesh, mapping=maps.IdentityMap(regMesh))

    # Optimization
    opt = optimization.InexactGaussNewton(maxIter=5)

    # statement of the inverse problem
    invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)

    # Inversion directives and parameters
    target = directives.TargetMisfit()  # stop when we hit target misfit
    invProb.beta = 2.0
    inv = inversion.BaseInversion(invProb, directiveList=[target])
    reg.alpha_s = 1e-3
    reg.alpha_x = 1.0
    reg.mref = m0.copy()
    opt.LSshorten = 0.5
    opt.remember("xc")
    # run the inversion
    mopt_re = inv.run(m0)
    dpred_re = invProb.dpred

    # ------------------ SkyTEM Forward Simulation ------------------ #
    # Step4: Invert SkyTEM data

    # Bird height from the surface
    b_height_skytem = skytem["src_elevation"].value
    src_height = b_height_skytem[rxind_skytem]
    srcLoc = np.array([0.0, 0.0, src_height])

    # Radius of the source loop
    area = skytem["area"].value
    radius = np.sqrt(area / np.pi)
    rxLoc = np.array([[radius, 0.0, src_height]])

    # Parameters for current waveform
    t0 = skytem["t0"].value
    times = skytem["times"].value
    waveform_skytem = skytem["waveform"].value
    offTime = t0
    times_off = times - t0

    # Note: we are Using theoretical VTEM waveform,
    # but effectively fits SkyTEM waveform
    peakTime = 1.0000000e-02
    a = 3.0

    dbdt_z = TDEM.Rx.PointMagneticFluxTimeDerivative(
        locations=rxLoc, times=times_off[:-3] + offTime,
        orientation="z")  # vertical db_dt

    rxList = [dbdt_z]  # list of receivers
    srcList = [
        TDEM.Src.CircularLoop(
            rxList,
            loc=srcLoc,
            radius=radius,
            orientation="z",
            waveform=TDEM.Src.VTEMWaveform(offTime=offTime,
                                           peakTime=peakTime,
                                           a=3.0),
        )
    ]
    # solve the problem at these times
    timeSteps = [
        (peakTime / 5, 5),
        ((offTime - peakTime) / 5, 5),
        (1e-5, 5),
        (5e-5, 5),
        (1e-4, 10),
        (5e-4, 15),
    ]
    prob = TDEM.Simulation3DElectricField(mesh,
                                          time_steps=timeSteps,
                                          sigmaMap=mapping,
                                          Solver=Solver)
    survey = TDEM.Survey(srcList)
    prob.survey = survey

    src = srcList[0]
    rx = src.receiver_list[0]
    wave = []
    for time in prob.times:
        wave.append(src.waveform.eval(time))
    wave = np.hstack(wave)
    out = prob.dpred(m0)

    # plot the waveform
    fig = plt.figure(figsize=(5, 3))
    times_off = times - t0
    plt.plot(waveform_skytem[:, 0], waveform_skytem[:, 1], "k.")
    plt.plot(prob.times, wave, "k-", lw=2)
    plt.legend(("SkyTEM waveform", "Waveform (fit)"), fontsize=10)
    for t in rx.times:
        plt.plot(np.ones(2) * t, np.r_[-0.03, 0.03], "k-")
    plt.ylim(-0.1, 1.1)
    plt.grid(True)
    plt.xlabel("Time (s)")
    plt.ylabel("Normalized current")

    if saveFig:
        fig.savefig("skytem_waveform", dpi=200)

    # Observed data
    dobs_sky = skytem["data"][rxind_skytem, :-3] * area

    # ------------------ SkyTEM Inversion ------------------ #
    # Uncertainty
    relative = 0.12
    floor = 7.5e-12
    std = abs(dobs_sky) * relative + floor

    # Data Misfit
    data_sky = data.Data(dobs=-dobs_sky, survey=survey, standard_deviation=std)
    dmisfit = data_misfit.L2DataMisfit(simulation=prob, data=data_sky)

    # Regularization
    regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
    reg = regularization.Simple(regMesh, mapping=maps.IdentityMap(regMesh))

    # Optimization
    opt = optimization.InexactGaussNewton(maxIter=5)

    # statement of the inverse problem
    invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt)

    # Directives and Inversion Parameters
    target = directives.TargetMisfit()
    invProb.beta = 20.0
    inv = inversion.BaseInversion(invProb, directiveList=[target])
    reg.alpha_s = 1e-1
    reg.alpha_x = 1.0
    opt.LSshorten = 0.5
    opt.remember("xc")
    reg.mref = mopt_re  # Use RESOLVE model as a reference model

    # run the inversion
    mopt_sky = inv.run(m0)
    dpred_sky = invProb.dpred

    # Plot the figure from the paper
    plt.figure(figsize=(12, 8))

    fs = 13  # fontsize
    matplotlib.rcParams["font.size"] = fs

    ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2)
    ax1 = plt.subplot2grid((2, 2), (0, 1))
    ax2 = plt.subplot2grid((2, 2), (1, 1))

    # Recovered Models
    sigma_re = np.repeat(np.exp(mopt_re), 2, axis=0)
    sigma_sky = np.repeat(np.exp(mopt_sky), 2, axis=0)
    z = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0)
    z = np.r_[mesh.vectorCCz[active][0], z, mesh.vectorCCz[active][-1]]

    ax0.semilogx(sigma_re, z, "k", lw=2, label="RESOLVE")
    ax0.semilogx(sigma_sky, z, "b", lw=2, label="SkyTEM")
    ax0.set_ylim(-50, 0)
    # ax0.set_xlim(5e-4, 1e2)
    ax0.grid(True)
    ax0.set_ylabel("Depth (m)")
    ax0.set_xlabel("Conducivity (S/m)")
    ax0.legend(loc=3)
    ax0.set_title("(a) Recovered Models")

    # RESOLVE Data
    ax1.loglog(frequency_cp,
               dobs_re.reshape((5, 2))[:, 0] / bp * 1e6,
               "k-",
               label="Obs (real)")
    ax1.loglog(
        frequency_cp,
        dobs_re.reshape((5, 2))[:, 1] / bp * 1e6,
        "k--",
        label="Obs (imag)",
    )
    ax1.loglog(
        frequency_cp,
        dpred_re.reshape((5, 2))[:, 0] / bp * 1e6,
        "k+",
        ms=10,
        markeredgewidth=2.0,
        label="Pred (real)",
    )
    ax1.loglog(
        frequency_cp,
        dpred_re.reshape((5, 2))[:, 1] / bp * 1e6,
        "ko",
        ms=6,
        markeredgecolor="k",
        markeredgewidth=0.5,
        label="Pred (imag)",
    )
    ax1.set_title("(b) RESOLVE")
    ax1.set_xlabel("Frequency (Hz)")
    ax1.set_ylabel("Bz (ppm)")
    ax1.grid(True)
    ax1.legend(loc=3, fontsize=11)

    # SkyTEM data
    ax2.loglog(times_off[3:] * 1e6, dobs_sky / area, "b-", label="Obs")
    ax2.loglog(
        times_off[3:] * 1e6,
        -dpred_sky / area,
        "bo",
        ms=4,
        markeredgecolor="k",
        markeredgewidth=0.5,
        label="Pred",
    )
    ax2.set_xlim(times_off.min() * 1e6 * 1.2, times_off.max() * 1e6 * 1.1)

    ax2.set_xlabel("Time ($\mu s$)")
    ax2.set_ylabel("dBz / dt (V/A-m$^4$)")
    ax2.set_title("(c) SkyTEM High-moment")
    ax2.grid(True)
    ax2.legend(loc=3)

    a3 = plt.axes([0.86, 0.33, 0.1, 0.09], facecolor=[0.8, 0.8, 0.8, 0.6])
    a3.plot(prob.times * 1e6, wave, "k-")
    a3.plot(rx.times * 1e6,
            np.zeros_like(rx.times),
            "k|",
            markeredgewidth=1,
            markersize=12)
    a3.set_xlim([prob.times.min() * 1e6 * 0.75, prob.times.max() * 1e6 * 1.1])
    a3.set_title("(d) Waveform", fontsize=11)
    a3.set_xticks([prob.times.min() * 1e6, t0 * 1e6, prob.times.max() * 1e6])
    a3.set_yticks([])
    # a3.set_xticklabels(['0', '2e4'])
    a3.set_xticklabels(["-1e4", "0", "1e4"])

    plt.tight_layout()

    if saveFig:
        plt.savefig("booky1D_time_freq.png", dpi=600)

    if plotIt:
        plt.show()

    resolve.close()
    skytem.close()
    if cleanup:
        print(os.path.split(directory)[:-1])
        os.remove(
            os.path.sep.join(directory.split()[:-1] +
                             ["._bookpurnong_inversion"]))
        os.remove(downloads)
        shutil.rmtree(directory)
예제 #10
0
    )
    rx_imag = FDEM.Rx.PointMagneticFluxDensitySecondary(
        locations=rx_locs, orientation=orientation, component="imag"
    )

    src = FDEM.Src.MagDipole(
        receiver_list=[rx_real, rx_imag],
        loc=src_loc,
        orientation=orientation,
        freq=freq,
    )

    srcList.append(src)

# create the survey and problem objects for running the forward simulation
survey = FDEM.Survey(srcList)
prob = FDEM.Simulation3DMagneticFluxDensity(
    mesh, survey=survey, sigmaMap=mapping, Solver=Solver
)

###############################################################################
# Set up data for inversion
# -------------------------
#
# Generate clean, synthetic data. Later we will invert the clean data, and
# assign a standard deviation of 0.05, and a floor of 1e-11.

t = time.time()

data = prob.make_synthetic_data(
    m_true, relative_error=0.05, noise_floor=1e-11, add_noise=False
예제 #11
0
 def survey(self):
     _survey = fdem.Survey(self.source.source_list)
     return _survey
예제 #12
0
def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False):
    cs = 10.0
    ncx, ncy, ncz = 0, 0, 0
    npad = 8
    hx = [(cs, npad, -1.3), (cs, ncx), (cs, npad, 1.3)]
    hy = [(cs, npad, -1.3), (cs, ncy), (cs, npad, 1.3)]
    hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)]
    mesh = TensorMesh([hx, hy, hz], ["C", "C", "C"])

    if useMu is True:
        mapping = [("sigma", maps.ExpMap(mesh)),
                   ("mu", maps.IdentityMap(mesh))]
    else:
        mapping = maps.ExpMap(mesh)

    x = (
        np.array([
            np.linspace(-5.0 * cs, -2.0 * cs, 3),
            np.linspace(5.0 * cs, 2.0 * cs, 3)
        ]) + cs / 4.0
    )  # don't sample right by the source, slightly off alignment from either staggered grid
    XYZ = utils.ndgrid(x, x, np.linspace(-2.0 * cs, 2.0 * cs, 5))
    Rx0 = getattr(fdem.Rx, "Point" + comp[0])
    if comp[-1] == "r":
        real_or_imag = "real"
    elif comp[-1] == "i":
        real_or_imag = "imag"
    rx0 = Rx0(XYZ, comp[1], real_or_imag)

    Src = []

    for SrcType in SrcList:
        if SrcType == "MagDipole":
            Src.append(
                fdem.Src.MagDipole([rx0],
                                   frequency=freq,
                                   location=np.r_[0.0, 0.0, 0.0]))
        elif SrcType == "MagDipole_Bfield":
            Src.append(
                fdem.Src.MagDipole_Bfield([rx0],
                                          frequency=freq,
                                          location=np.r_[0.0, 0.0, 0.0]))
        elif SrcType == "CircularLoop":
            Src.append(
                fdem.Src.CircularLoop([rx0],
                                      frequency=freq,
                                      location=np.r_[0.0, 0.0, 0.0]))
        elif SrcType == "LineCurrent":
            Src.append(
                fdem.Src.LineCurrent(
                    [rx0],
                    frequency=freq,
                    location=np.array([[0.0, 0.0, 0.0], [20.0, 0.0, 0.0]]),
                ))
        elif SrcType == "RawVec":
            if fdemType == "e" or fdemType == "b":
                S_m = np.zeros(mesh.nF)
                S_e = np.zeros(mesh.nE)
                S_m[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Fz") +
                    np.sum(mesh.vnF[:1])] = 1e-3
                S_e[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Ez") +
                    np.sum(mesh.vnE[:1])] = 1e-3
                Src.append(
                    fdem.Src.RawVec([rx0], freq, S_m,
                                    mesh.getEdgeInnerProduct() * S_e))

            elif fdemType == "h" or fdemType == "j":
                S_m = np.zeros(mesh.nE)
                S_e = np.zeros(mesh.nF)
                S_m[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Ez") +
                    np.sum(mesh.vnE[:1])] = 1e-3
                S_e[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Fz") +
                    np.sum(mesh.vnF[:1])] = 1e-3
                Src.append(
                    fdem.Src.RawVec([rx0], freq,
                                    mesh.getEdgeInnerProduct() * S_m, S_e))

    if verbose:
        print("  Fetching {0!s} problem".format((fdemType)))

    if fdemType == "e":
        survey = fdem.Survey(Src)
        prb = fdem.Simulation3DElectricField(mesh, sigmaMap=mapping)

    elif fdemType == "b":
        survey = fdem.Survey(Src)
        prb = fdem.Simulation3DMagneticFluxDensity(mesh, sigmaMap=mapping)

    elif fdemType == "j":
        survey = fdem.Survey(Src)
        prb = fdem.Simulation3DCurrentDensity(mesh, sigmaMap=mapping)

    elif fdemType == "h":
        survey = fdem.Survey(Src)
        prb = fdem.Simulation3DMagneticField(mesh, sigmaMap=mapping)

    else:
        raise NotImplementedError()
    prb.pair(survey)

    try:
        from pymatsolver import Pardiso

        prb.solver = Pardiso
    except ImportError:
        prb.solver = SolverLU
    # prb.solver_opts = dict(check_accuracy=True)

    return prb
예제 #13
0
    bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
        receiver_locations[ii, :], "z", "imag")
    bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
        receiver_locations[ii, :], "z", "imag")
    receivers_list = [bzr_receiver, bzi_receiver]

    # Must define the transmitter properties and associated receivers
    source_location = receiver_locations[ii, :] + np.c_[0, 0, 20]

    source_list.append(
        fdem.sources.MagDipole(receivers_list,
                               frequencies[ii],
                               source_location,
                               orientation="z"))

survey = fdem.Survey(source_list)

#############################################
# Defining the Data
# -----------------
#
# Here is where we define the data that are inverted. The data are defined by
# the survey, the observation values and the uncertainties.
#

mu0 = 4 * np.pi * 1e-7
dobs = mkvc(np.c_[dobs_real, dobs_imag].T)
uncertainties = mkvc(np.c_[uncertainties_real, uncertainties_imag].T)

data_object = data.Data(survey, dobs=dobs, noise_floor=uncertainties)
예제 #14
0
def setupProblem(
    mesh,
    muMod,
    sigmaMod,
    prbtype="ElectricField",
    invertMui=False,
    sigmaInInversion=False,
    freq=1.0,
):
    rxcomp = ["real", "imag"]

    loc = utils.ndgrid([mesh.vectorCCx, np.r_[0.0], mesh.vectorCCz])

    if prbtype in ["ElectricField", "MagneticFluxDensity"]:
        rxfields_y = ["ElectricField", "CurrentDensity"]
        rxfields_xz = ["MagneticFluxDensity", "MagneticField"]

    elif prbtype in ["MagneticField", "CurrentDensity"]:
        rxfields_y = ["MagneticFluxDensity", "MagneticField"]
        rxfields_xz = ["ElectricField", "CurrentDensity"]

    receiver_list_edge = [
        getattr(fdem.receivers, "Point{f}".format(f=f))(loc,
                                                        component=comp,
                                                        orientation=orient)
        for f in rxfields_y for comp in rxcomp for orient in ["y"]
    ]

    receiver_list_face = [
        getattr(fdem.receivers, "Point{f}".format(f=f))(loc,
                                                        component=comp,
                                                        orientation=orient)
        for f in rxfields_xz for comp in rxcomp for orient in ["x", "z"]
    ]

    receiver_list = receiver_list_edge + receiver_list_face

    src_loc = np.r_[0.0, 0.0, 0.0]

    if prbtype in ["ElectricField", "MagneticFluxDensity"]:
        src = fdem.sources.MagDipole(receiver_list=receiver_list,
                                     location=src_loc,
                                     frequency=freq)

    elif prbtype in ["MagneticField", "CurrentDensity"]:
        ind = utils.closestPoints(mesh, src_loc, "Fz") + mesh.vnF[0]
        vec = np.zeros(mesh.nF)
        vec[ind] = 1.0

        src = fdem.sources.RawVec_e(receiver_list=receiver_list,
                                    frequency=freq,
                                    s_e=vec)

    survey = fdem.Survey([src])

    if sigmaInInversion:

        wires = maps.Wires(("mu", mesh.nC), ("sigma", mesh.nC))

        muMap = maps.MuRelative(mesh) * wires.mu
        sigmaMap = maps.ExpMap(mesh) * wires.sigma

        if invertMui:
            muiMap = maps.ReciprocalMap(mesh) * muMap
            prob = getattr(fdem,
                           "Simulation3D{}".format(prbtype))(mesh,
                                                             muiMap=muiMap,
                                                             sigmaMap=sigmaMap)
            # m0 = np.hstack([1./muMod, sigmaMod])
        else:
            prob = getattr(fdem,
                           "Simulation3D{}".format(prbtype))(mesh,
                                                             muMap=muMap,
                                                             sigmaMap=sigmaMap)
        m0 = np.hstack([muMod, sigmaMod])

    else:
        muMap = maps.MuRelative(mesh)

        if invertMui:
            muiMap = maps.ReciprocalMap(mesh) * muMap
            prob = getattr(fdem,
                           "Simulation3D{}".format(prbtype))(mesh,
                                                             sigma=sigmaMod,
                                                             muiMap=muiMap)
            # m0 = 1./muMod
        else:
            prob = getattr(fdem,
                           "Simulation3D{}".format(prbtype))(mesh,
                                                             sigma=sigmaMod,
                                                             muMap=muMap)
        m0 = muMod

    prob.survey = survey

    return m0, prob, survey
예제 #15
0
    rx_real = FDEM.Rx.PointMagneticFluxDensitySecondary(
        locations=rx_locs, orientation=orientation, component="real")
    rx_imag = FDEM.Rx.PointMagneticFluxDensitySecondary(
        locations=rx_locs, orientation=orientation, component="imag")

    src = FDEM.Src.MagDipole(
        receiver_list=[rx_real, rx_imag],
        location=src_loc,
        orientation=orientation,
        frequency=freq,
    )

    source_list.append(src)

# create the survey and problem objects for running the forward simulation
survey = FDEM.Survey(source_list)
prob = FDEM.Simulation3DMagneticFluxDensity(mesh,
                                            survey=survey,
                                            sigmaMap=mapping,
                                            solver=Solver)

###############################################################################
# Set up data for inversion
# -------------------------
#
# Generate clean, synthetic data. Later we will invert the clean data, and
# assign a standard deviation of 0.05, and a floor of 1e-11.

t = time.time()

data = prob.make_synthetic_data(m_true,
예제 #16
0
def fdem_forward_simulation(detector, target, collection):
    """
    Get FDEM simulation data using SimPEG.

    Parameters
    ----------
    detector : class Detector
    target : class Target
    collention : class Collection

    Returns
    -------
    receiver_locations : numpy.ndarray, shape(N * 3)
        All acquisition locations of the detector. Each row represents an
        acquisition location and the three columns represent x, y and z axis
        locations of an acquisition location.
    mag_data : numpy.ndarray, shape(N*3)
        All secondary fields of acquisition locations.
    mesh : SimPEG mesh
    mapped_model : numpy.ndarray

    References
    ----------
    https://docs.simpeg.xyz/content/tutorials/01-models_mapping/plot_1_tensor_models.html#sphx-glr-content-tutorials-01-models-mapping-plot-1-tensor-models-py
    http://discretize.simpeg.xyz/en/master/tutorials/mesh_generation/4_tree_mesh.html#sphx-glr-tutorials-mesh-generation-4-tree-mesh-py
    https://docs.simpeg.xyz/content/tutorials/07-fdem/plot_fwd_2_fem_cyl.html#sphx-glr-content-tutorials-07-fdem-plot-fwd-2-fem-cyl-py
    https://docs.simpeg.xyz/content/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.html#sphx-glr-content-examples-05-fdem-plot-inv-fdem-loop-loop-2dinversion-py

    """

    # Frequencies being predicted
    frequencies = [detector.frequency]

    # Conductivity in S/m (or resistivity in Ohm m)
    background_conductivity = 1e-6
    air_conductivity = 1e-8

    # Permeability in H/m
    background_permeability = mu_0
    air_permeability = mu_0
    """Survey"""

    # Defining transmitter locations
    acquisition_spacing = collection.spacing
    acq_area_xmin, acq_area_xmax = collection.x_min, collection.x_max
    acq_area_ymin, acq_area_ymax = collection.y_min, collection.y_max
    Nx = int((acq_area_xmax - acq_area_xmin) / acquisition_spacing + 1)
    Ny = int((acq_area_ymax - acq_area_ymin) / acquisition_spacing + 1)
    xtx, ytx, ztx = np.meshgrid(np.linspace(acq_area_xmin, acq_area_xmax, Nx),
                                np.linspace(acq_area_ymin, acq_area_ymax, Ny),
                                [collection.height])
    source_locations = np.c_[mkvc(xtx), mkvc(ytx), mkvc(ztx)]
    ntx = np.size(xtx)

    # Define receiver locations
    xrx, yrx, zrx = np.meshgrid(np.linspace(acq_area_xmin, acq_area_xmax, Nx),
                                np.linspace(acq_area_ymin, acq_area_ymax, Ny),
                                [collection.height])
    receiver_locations = np.c_[mkvc(xrx), mkvc(yrx), mkvc(zrx)]

    # Create empty list to store sources
    source_list = []

    # Each unique location and frequency defines a new transmitter
    for ii in range(len(frequencies)):
        for jj in range(ntx):

            # Define receivers of different type at each location
            bxr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "x", "real")
            bxi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "x", "imag")
            byr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "y", "real")
            byi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "y", "imag")
            bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "z", "real")
            bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary(
                receiver_locations[jj, :], "z", "imag")
            receivers_list = [
                bxr_receiver, bxi_receiver, byr_receiver, byi_receiver,
                bzr_receiver, bzi_receiver
            ]

            # Must define the transmitter properties and associated receivers
            source_list.append(
                fdem.sources.MagDipole(receivers_list,
                                       frequencies[ii],
                                       source_locations[jj],
                                       orientation="z",
                                       moment=detector.get_mag_moment()))

    survey = fdem.Survey(source_list)
    '''Mesh'''

    dh = 0.1  # base cell width
    dom_width = 20.0  # domain width
    # num. base cells
    nbc = 2**int(np.round(np.log(dom_width / dh) / np.log(2.0)))

    # Define the base mesh
    h = [(dh, nbc)]
    mesh = TreeMesh([h, h, h], x0="CCC")

    # Mesh refinement near transmitters and receivers
    mesh = refine_tree_xyz(mesh,
                           receiver_locations,
                           octree_levels=[2, 4],
                           method="radial",
                           finalize=False)

    # Refine core mesh region
    xp, yp, zp = np.meshgrid([-1.5, 1.5], [-1.5, 1.5], [-6, -4])
    xyz = np.c_[mkvc(xp), mkvc(yp), mkvc(zp)]
    mesh = refine_tree_xyz(mesh,
                           xyz,
                           octree_levels=[0, 6],
                           method="box",
                           finalize=False)

    mesh.finalize()
    '''Maps'''

    # Find cells that are active in the forward modeling (cells below surface)
    ind_active = mesh.gridCC[:, 2] < 0

    # Define mapping from model to active cells
    active_sigma_map = maps.InjectActiveCells(mesh, ind_active,
                                              air_conductivity)
    active_mu_map = maps.InjectActiveCells(mesh, ind_active, air_permeability)

    # Define model. Models in SimPEG are vector arrays
    N = int(ind_active.sum())
    model = np.kron(np.ones((N, 1)), np.c_[background_conductivity,
                                           background_permeability])

    ind_cylinder = getIndicesCylinder(
        [target.position[0], target.position[1], target.position[2]],
        target.radius, target.length, [target.pitch, target.roll], mesh.gridCC)
    ind_cylinder = ind_cylinder[ind_active]
    model[ind_cylinder, :] = np.c_[target.conductivity, target.permeability]

    # Create model vector and wires
    model = mkvc(model)
    wire_map = maps.Wires(("sigma", N), ("mu", N))

    # Use combo maps to map from model to mesh
    sigma_map = active_sigma_map * wire_map.sigma
    mu_map = active_mu_map * wire_map.mu
    '''Simulation'''

    simulation = fdem.simulation.Simulation3DMagneticFluxDensity(
        mesh, survey=survey, sigmaMap=sigma_map, muMap=mu_map, Solver=Solver)
    '''Predict'''

    # Compute predicted data for a your model.
    dpred = simulation.dpred(model)
    dpred = dpred * 1e9

    # Data are organized by frequency, transmitter location, then by receiver.
    # We had nFreq transmitters and each transmitter had 2 receivers (real and
    # imaginary component). So first we will pick out the real and imaginary
    # data
    bx_real = dpred[0:len(dpred):6]
    bx_imag = dpred[1:len(dpred):6]
    bx_total = np.sqrt(np.square(bx_real) + np.square(bx_imag))
    by_real = dpred[2:len(dpred):6]
    by_imag = dpred[3:len(dpred):6]
    by_total = np.sqrt(np.square(by_real) + np.square(by_imag))
    bz_real = dpred[4:len(dpred):6]
    bz_imag = dpred[5:len(dpred):6]
    bz_total = np.sqrt(np.square(bz_real) + np.square(bz_imag))

    mag_data = np.c_[mkvc(bx_total), mkvc(by_total), mkvc(bz_total)]

    return receiver_locations, mag_data, mesh, sigma_map * model