Esempio n. 1
0
    def activeCells(self):
        if getattr(self, '_activeCells', None) is None:
            if getattr(self, 'topofile', None) is not None:
                topo = np.genfromtxt(self.basePath + self.topofile,
                                     skip_header=1)
                # Find the active cells
                active = Utils.surface2ind_topo(self.mesh, topo, 'N')

            elif isinstance(self._staticInput, float):
                active = self.m0 != self._staticInput

            else:
                # Read from file active cells with 0:air, 1:dynamic, -1 static
                active = self.activeModel != 0

            inds = np.asarray(
                [inds for inds, elem in enumerate(active, 1) if elem],
                dtype=int) - 1

            self._activeCells = inds

            # Reduce m0 to active space
            if len(self.m0) > len(self._activeCells):
                self._m0 = self.m0[self._activeCells]

        return self._activeCells
Esempio n. 2
0
def drapeTopotoLoc(mesh, pts, actind=None, option="top", topo=None):
    """
        Drape location right below (cell center) the topography
    """
    if mesh.dim == 2:
        if pts.ndim > 1:
            raise Exception("pts should be 1d array")
    elif mesh.dim == 3:
        if pts.shape[1] == 3:
            raise Exception("shape of pts should be (x,3)")
    else:
        raise NotImplementedError()
    if actind is None:
        actind = Utils.surface2ind_topo(mesh, topo)
    if mesh._meshType == "TENSOR":
        meshtemp, topoCC = gettopoCC(mesh, actind, option=option)
        inds = Utils.closestPoints(meshtemp, pts)

    elif mesh._meshType == "TREE":
        if mesh.dim == 3:
            uniqXYlocs, topoCC = gettopoCC(mesh, actind, option=option)
            inds = closestPointsGrid(uniqXYlocs, pts)
        else:
            raise NotImplementedError()
    else:
        raise NotImplementedError()
    out = np.c_[pts, topoCC[inds]]
    return out
Esempio n. 3
0
    def activeCells(self):
        if getattr(self, '_activeCells', None) is None:
            if getattr(self, 'topofile', None) is not None:
                topo = np.genfromtxt(
                    self.basePath + self.topofile, skip_header=1
                )

                # Find the active cells
                active = Utils.surface2ind_topo(self.mesh, topo, 'N')

            elif isinstance(self._staticInput, float):
                active = self.m0 != self._staticInput

            else:
                # Read from file active cells with 0:air, 1:dynamic, -1 static
                active = self.activeModel != 0

            inds = np.where(active)[0]

            self._activeCells = inds

            # Reduce m0 to active space
            if len(self.m0) > len(self._activeCells):
                self._m0 = self.m0[self._activeCells]

        return self._activeCells
Esempio n. 4
0
def drapeTopotoLoc(mesh, pts, actind=None, option="top", topo=None):
    """
        Drape location right below (cell center) the topography
    """
    if mesh.dim == 2:
        if pts.ndim > 1:
            raise Exception("pts should be 1d array")
    elif mesh.dim == 3:
        if pts.shape[1] == 3:
            raise Exception("shape of pts should be (x,3)")
    else:
        raise NotImplementedError()
    if actind is None:
        actind = Utils.surface2ind_topo(mesh, topo)
    if mesh._meshType == "TENSOR":
        meshtemp, topoCC = gettopoCC(mesh, actind, option=option)
        inds = Utils.closestPoints(meshtemp, pts)

    elif mesh._meshType == "TREE":
        if mesh.dim == 3:
            uniqXYlocs, topoCC = gettopoCC(mesh, actind, option=option)
            inds = closestPointsGrid(uniqXYlocs, pts)
        else:
            raise NotImplementedError()
    else:
        raise NotImplementedError()
    out = np.c_[pts, topoCC[inds]]
    return out
Esempio n. 5
0
    def activeCells(self):
        if getattr(self, '_activeCells', None) is None:
            if getattr(self, 'topofile', None) is not None:
                topo = np.genfromtxt(self.basePath + self.topofile,
                                     skip_header=1)
                # Find the active cells
                active = Utils.surface2ind_topo(self.mesh, topo, 'N')

            elif isinstance(self._staticInput, float):
                active = self.m0 != self._staticInput

            else:
                # Read from file active cells with 0:air, 1:dynamic, -1 static
                active = self.activeModel != 0

            inds = np.asarray([inds for inds,
                               elem in enumerate(active, 1)
                               if elem], dtype=int) - 1

            self._activeCells = inds

            # Reduce m0 to active space
            self._m0 = self.m0[self._activeCells]

        return self._activeCells
Esempio n. 6
0
def create_local_mesh(
    src_location,
    rx_location,
    topo_location,
    topo,
    h = [10., 10., 5.],
    x_core_lim = (-100., 100.),
    y_core_lim = (-20., 20.),
    ):

    # TODO: All parameters used for generating this mesh should be input parameters
    # Currently fixed for a specific case

    xyz = np.vstack((rx_location, src_location))
    x = np.linspace(x_core_lim[0], x_core_lim[1]) + src_location[0]
    y = np.linspace(y_core_lim[0], y_core_lim[1]) + src_location[1]
    dem = Utils.ndgrid(x, y, np.r_[topo_location[2]])

    mesh_local = discretize.utils.mesh_builder_xyz(
        dem,
        h,
        padding_distance=[[2000., 2000.], [2000., 2000.], [2000., 2000.]],
        base_mesh=None,
        depth_core=None,
        expansion_factor=1.3,
        mesh_type='tree'
    )

    mesh_local = discretize.utils.refine_tree_xyz(
        mesh_local,
        dem,
        method='surface',
        octree_levels=[5, 10, 10],
        octree_levels_padding=None,
        finalize=False,
        min_level=0,
        max_distance=np.inf,
    )


    mesh_local = discretize.utils.refine_tree_xyz(
        mesh_local,
        xyz,
        method='radial',
        octree_levels=[2, 0, 0],
        octree_levels_padding=None,
        finalize=True,
        min_level=1,
        max_distance=np.inf,
    )

    actv_local = Utils.surface2ind_topo(mesh_local, topo)

    return mesh_local, actv_local
Esempio n. 7
0
    def activeCells(self):
        if getattr(self, '_activeCells', None) is None:
            if self.topofile == 'null':
                self._activeCells = np.arange(mesh.nC)
            else:
                topo = np.genfromtxt(self.basePath + self.topofile, skip_header=1)
                # Find the active cells
                active = Utils.surface2ind_topo(self.mesh,topo,'N')
                inds = np.asarray([inds for inds, elem in enumerate(active, 1) if elem], dtype = int) - 1
                self._activeCells = inds

        return self._activeCells
Esempio n. 8
0
def readSeepageModel(fname, mesh=None, xsurf=None, ysurf=None):

    fluiddata = pd.read_csv(fname)
    header = fluiddata.keys()
    xyz = np.c_[fluiddata['X (m)'].values,fluiddata['Y (m)'].values]
    h = fluiddata['Total Head (m)'].values
    Ux = fluiddata['X-Velocity Magnitude (m/sec)'].values
    Uy = fluiddata['Y-Velocity Magnitude (m/sec)'].values
    Gradx = fluiddata['X-Gradient'].values
    Grady = fluiddata['Y-Gradient'].values

    Pressure = fluiddata['Pressure Head (m)'].values
    Sw = fluiddata[fluiddata.keys()[17]].values
    Kx = fluiddata["X-Conductivity (m/sec)"]
    Ky = fluiddata["Y-Conductivity (m/sec)"]

    if mesh is None:
        # TODO: this is a specific set up ...
        xmin, ymin = xyz[:,0].min(), xyz[:,1].min()
        cs = 0.5
        ncx = 152*2
        ncy = 36*2
        npad = 5
        hx = [(cs,npad, -1.3),(cs,ncx),(cs,npad, 1.3)]
        hy = [(cs,npad, -1.3),(cs,ncy)]
        mesh = Mesh.TensorMesh([hx, hy], x0 = [xmin, ymin])
        mesh._x0 = np.r_[xmin-mesh.hx[:10].sum(), xmin-mesh.hy[:10].sum()]
        # ...
        xsurf = np.r_[-1e10, 55, 90, 94, 109, 112, 126.5, +1e10]
        ysurf = np.r_[27.5, 27.5, 43.2, 43.2, 35, 35, 27.5, 27.5]
        yup = np.ones_like(ysurf)*45
        actind = Utils.surface2ind_topo(mesh, np.c_[xsurf, ysurf])
        waterheight = 40.
        waterind = (np.logical_and(~actind, mesh.gridCC[:,1]<40.)) & (mesh.gridCC[:,0]<90.)


    F_hlin = LinearNDInterpolator(xyz, h)
    hccIn = F_hlin(mesh.gridCC[actind,:])
    F_hnear = NearestNDInterpolator(mesh.gridCC[actind,:], hccIn)
    hcc = F_hnear(mesh.gridCC)

    fluiddata = {"xyz": xyz, "h":h, "Sw":Sw, "Kx":Kx, "Ky":Ky, "P":Pressure, "Ux":Ux, "Uy":Uy,\
                 "Gradx":Gradx, "Grady":Grady, \
                 "hcc": hcc, "mesh":mesh, "actind":actind, "waterind": waterind, \
                 "xsurf":xsurf, "ysurf":ysurf, "yup":yup}

    return fluiddata
Esempio n. 9
0
def readSeepageModel(fname, mesh=None, xsurf=None, ysurf=None):

    fluiddata = pd.read_csv(fname)
    header = fluiddata.keys()
    xyz = np.c_[fluiddata['X (m)'].values, fluiddata['Y (m)'].values]
    h = fluiddata['Total Head (m)'].values
    Ux = fluiddata['X-Velocity Magnitude (m/sec)'].values
    Uy = fluiddata['Y-Velocity Magnitude (m/sec)'].values
    Gradx = fluiddata['X-Gradient'].values
    Grady = fluiddata['Y-Gradient'].values

    Pressure = fluiddata['Pressure Head (m)'].values
    Sw = fluiddata[fluiddata.keys()[17]].values
    Kx = fluiddata["X-Conductivity (m/sec)"]
    Ky = fluiddata["Y-Conductivity (m/sec)"]

    if mesh is None:
        # TODO: this is a specific set up ...
        xmin, ymin = xyz[:, 0].min(), xyz[:, 1].min()
        cs = 0.5
        ncx = 152 * 2
        ncy = 36 * 2
        npad = 5
        hx = [(cs, npad, -1.3), (cs, ncx), (cs, npad, 1.3)]
        hy = [(cs, npad, -1.3), (cs, ncy)]
        mesh = Mesh.TensorMesh([hx, hy], x0=[xmin, ymin])
        mesh._x0 = np.r_[xmin - mesh.hx[:10].sum(), xmin - mesh.hy[:10].sum()]
        # ...
        xsurf = np.r_[-1e10, 55, 90, 94, 109, 112, 126.5, +1e10]
        ysurf = np.r_[27.5, 27.5, 43.2, 43.2, 35, 35, 27.5, 27.5]
        yup = np.ones_like(ysurf) * 45
        actind = Utils.surface2ind_topo(mesh, np.c_[xsurf, ysurf])
        waterheight = 40.
        waterind = (np.logical_and(
            ~actind, mesh.gridCC[:, 1] < 40.)) & (mesh.gridCC[:, 0] < 90.)

    F_hlin = LinearNDInterpolator(xyz, h)
    hccIn = F_hlin(mesh.gridCC[actind, :])
    F_hnear = NearestNDInterpolator(mesh.gridCC[actind, :], hccIn)
    hcc = F_hnear(mesh.gridCC)

    fluiddata = {"xyz": xyz, "h":h, "Sw":Sw, "Kx":Kx, "Ky":Ky, "P":Pressure, "Ux":Ux, "Uy":Uy,\
                 "Gradx":Gradx, "Grady":Grady, \
                 "hcc": hcc, "mesh":mesh, "actind":actind, "waterind": waterind, \
                 "xsurf":xsurf, "ysurf":ysurf, "yup":yup}

    return fluiddata
Esempio n. 10
0
    def get_interpolation_matrix(
        self,
        npts=20,
        epsilon=None
    ):

        tree_2d = kdtree(self.topography[:, :2])
        xy = Utils.ndgrid(self.mesh_3d.vectorCCx, self.mesh_3d.vectorCCy)

        distance, inds = tree_2d.query(xy, k=npts)
        if epsilon is None:
            epsilon = np.min([self.mesh_3d.hx.min(), self.mesh_3d.hy.min()])

        w = 1. / (distance + epsilon)**2
        w = Utils.sdiag(1./np.sum(w, axis=1)) * (w)
        I = Utils.mkvc(
            np.arange(inds.shape[0]).reshape([-1, 1]).repeat(npts, axis=1)
        )
        J = Utils.mkvc(inds)

        self._P = sp.coo_matrix(
            (Utils.mkvc(w), (I, J)),
            shape=(inds.shape[0], self.topography.shape[0])
        )

        mesh_1d = Mesh.TensorMesh([np.r_[self.hz[:-1], 1e20]])

        z = self.P*self.topography[:, 2]

        self._actinds = Utils.surface2ind_topo(self.mesh_3d, np.c_[xy, z])

        Z = np.empty(self.mesh_3d.vnC, dtype=float, order='F')
        Z = self.mesh_3d.gridCC[:, 2].reshape(
            (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F'
        )
        ACTIND = self._actinds.reshape(
            (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F'
        )

        self._Pz = []

        # This part can be cythonized or parallelized
        for i_xy in range(self.mesh_3d.nCx*self.mesh_3d.nCy):
            actind_temp = ACTIND[i_xy, :]
            z_temp = -(Z[i_xy, :] - z[i_xy])
            self._Pz.append(mesh_1d.getInterpolationMat(z_temp[actind_temp]))
Esempio n. 11
0
def drapeTopotoLoc(mesh, topo, pts):
    """
        Drape
    """
    if mesh.dim == 2:
        if pts.ndim > 1:
            raise Exception("pts should be 1d array")
    elif mesh.dim == 3:
        if pts.shape[1] == 3:
            raise Exception("shape of pts should be (x,3)")
    else:
        raise NotImplementedError()
    airind = Utils.surface2ind_topo(mesh, topo)
    meshtemp, topoCC = gettopoCC(mesh, ~airind)
    inds = Utils.closestPoints(meshtemp, pts)

    return np.c_[pts, topoCC[inds]]
Esempio n. 12
0
def drapeTopotoLoc(mesh, topo, pts):
    """
        Drape
    """
    if mesh.dim ==2:
        if pts.ndim > 1:
            raise Exception("pts should be 1d array")
    elif mesh.dim ==3:
        if pts.shape[1] == 3:
            raise Exception("shape of pts should be (x,3)")
    else:
        raise NotImplementedError()
    airind = Utils.surface2ind_topo(mesh, topo)
    meshtemp, topoCC = gettopoCC(mesh, ~airind)
    inds = Utils.closestPoints(meshtemp, pts)

    return np.c_[pts, topoCC[inds]]
Esempio n. 13
0
    def get_interpolation_matrix(
        self,
        npts=20,
        epsilon=None
    ):

        tree_2d = kdtree(self.topography[:, :2])
        xy = Utils.ndgrid(self.mesh_3d.vectorCCx, self.mesh_3d.vectorCCy)

        distance, inds = tree_2d.query(xy, k=npts)
        if epsilon is None:
            epsilon = np.min([self.mesh_3d.hx.min(), self.mesh_3d.hy.min()])

        w = 1. / (distance + epsilon)**2
        w = Utils.sdiag(1./np.sum(w, axis=1)) * (w)
        I = Utils.mkvc(
            np.arange(inds.shape[0]).reshape([-1, 1]).repeat(npts, axis=1)
        )
        J = Utils.mkvc(inds)

        self._P = sp.coo_matrix(
            (Utils.mkvc(w), (I, J)),
            shape=(inds.shape[0], self.topography.shape[0])
        )

        mesh_1d = Mesh.TensorMesh([np.r_[self.hz[:-1], 1e20]])

        z = self.P*self.topography[:, 2]

        self._actinds = Utils.surface2ind_topo(self.mesh_3d, np.c_[xy, z])

        Z = np.empty(self.mesh_3d.vnC, dtype=float, order='F')
        Z = self.mesh_3d.gridCC[:, 2].reshape(
            (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F'
        )
        ACTIND = self._actinds.reshape(
            (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F'
        )

        self._Pz = []

        # This part can be cythonized or parallelized
        for i_xy in range(self.mesh_3d.nCx*self.mesh_3d.nCy):
            actind_temp = ACTIND[i_xy, :]
            z_temp = -(Z[i_xy, :] - z[i_xy])
            self._Pz.append(mesh_1d.getInterpolationMat(z_temp[actind_temp]))
Esempio n. 14
0
    def setUp(self):

        ndv = -100
        # Create a self.mesh
        dx = 5.

        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 = Mesh.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., 20., 20)
        yr = np.linspace(-20., 20., 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.

        # Create a MAGsurvey
        locXYZ = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        rxLoc = PF.BaseGrav.RxObs(locXYZ)
        srcField = PF.BaseGrav.SrcField([rxLoc])
        survey = PF.BaseGrav.LinearSurvey(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
        prob = PF.Gravity.GravityIntegral(
            self.mesh,
            rhoMap=idenMap,
            actInd=actv
        )

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

        # Compute linear forward operator and compute some data
        d = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        data = d + np.random.randn(len(d))*0.001
        wd = np.ones(len(data))*.001

        survey.dobs = data
        survey.std = wd

        # PF.Gravity.plot_obs_2D(survey.srcField.rxList[0].locs, d=data)

        # Create sensitivity weights from our linear forward operator
        wr = PF.Magnetics.get_dist_wgt(self.mesh, locXYZ, actv, 2., 2.)
        wr = wr**2.

        # Create a regularization
        reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap)
        reg.cell_weights = wr
        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 = DataMisfit.l2_DataMisfit(survey)
        dmis.W = 1/wd

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=100, lower=-1., upper=1.,
                                         maxIterLS=20, maxIterCG=10,
                                         tolCG=1e-3)
        invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+8)

        # Here is where the norms are applied
        IRLS = Directives.Update_IRLS(f_min_change=1e-4,
                                      minGNiter=1)
        update_Jacobi = Directives.UpdatePreconditioner()

        self.inv = Inversion.BaseInversion(invProb,
                                           directiveList=[IRLS,
                                                          update_Jacobi])
Esempio n. 15
0
    # level means number of layers in current OcTree level
    for level in range(int(nCpad[ii])):

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

        zOffset += dx

mesh.finalize()

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

###########################################################################
# Forward modeling data
# ---------------------
#
# We can now generate TMI data
#

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

# Get the indicies of the magnetized block
ind = Utils.ModelBuilder.getIndicesBlock(
    np.r_[-20, -20, -10], np.r_[20, 20, 25],
Esempio n. 16
0
    def set_mesh(self, topo=None,
                dx=None, dy=None, dz=None,
                n_spacing=None, corezlength=None,
                npad_x=7, npad_y=7, npad_z=7,
                pad_rate_x=1.3, pad_rate_y=1.3, pad_rate_z=1.3,
                ncell_per_dipole=4, mesh_type='TensorMesh',
                dimension=2,
                method='nearest'
                ):
        """
        Set up a mesh for a given DC survey
        """
        if mesh_type == 'TreeMesh':
            raise NotImplementedError()

        # 2D or 3D mesh
        if dimension in [2, 3]:
            if dimension == 2:
                z_ind = 1
            else:
                z_ind = 2
            a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min()
            lineLength = abs(
                self.electrode_locations[:, 0].max() -
                self.electrode_locations[:, 0].min()
            )
            dx_ideal = a/ncell_per_dipole
            if dx is None:
                dx = dx_ideal
                warnings.warn(
                    "dx is set to {} m (samllest electrode spacing ({}) / {})".format(dx, a, ncell_per_dipole)
                )
            if dz is None:
                dz = dx*0.5
                warnings.warn(
                    "dz ({} m) is set to dx ({} m) / {}".format(dz, dx, 2)
                )
            x0 = self.electrode_locations[:, 0].min()
            if topo is None:
                # For 2D mesh
                if dimension == 2:
                    # sort by x
                    row_idx = np.lexsort((self.electrode_locations[:, 0],))
                # For 3D mesh
                else:
                    # sort by x, then by y
                    row_idx = np.lexsort((self.electrode_locations[:, 1],
                                          self.electrode_locations[:, 0]))
                locs = self.electrode_locations[row_idx, :]
            else:
                # For 2D mesh
                if dimension == 2:
                    # sort by x
                    mask = np.isin(self.electrode_locations[:, 0], topo[:, 0])
                    if np.any(mask):
                        raise RuntimeError("the x coordinates of some topo and electrodes are the same.")
                    locs_tmp = np.vstack((topo, self.electrode_locations[~mask, :]))
                    row_idx = np.lexsort((locs_tmp[:, 0],))
                # For 3D mesh
                else:
                    # sort by x, then by y
                    dtype = [('x', np.float64), ('y', np.float64)]
                    mask = np.isin(self.electrode_locations[:, [0, 1]].copy().view(dtype),
                                   topo[:, [0, 1]].copy().view(dtype)).flatten()
                    if np.any(mask):
                        raise RuntimeError("the x and y coordinates of some topo and electrodes are the same.")
                    locs_tmp = np.vstack((topo, self.electrode_locations[~mask, :]))
                    row_idx = np.lexsort((locs_tmp[:, 1], locs_tmp[:, 0]))
                locs = locs_tmp[row_idx, :]

            if dx > dx_ideal:
                # warnings.warn(
                #     "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a)
                # )
                pass
            self.dx = dx
            self.dz = dz
            self.npad_x = npad_x
            self.npad_z = npad_z
            self.pad_rate_x = pad_rate_x
            self.pad_rate_z = pad_rate_z
            self.ncell_per_dipole = ncell_per_dipole
            zmax = locs[:, z_ind].max()
            zmin = locs[:, z_ind].min()

            # 3 cells each for buffer
            corexlength = lineLength + dx * 6
            if corezlength is None:
                corezlength = self.grids[:, z_ind].max()

            ncx = np.round(corexlength/dx)
            ncz = np.round(corezlength/dz)
            hx = [
                (dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x)
            ]
            hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)]
            x0_mesh = -(
                (dx * pad_rate_x ** (np.arange(npad_x)+1)).sum() + dx * 3 - x0
            )
            z0_mesh = -((dz * pad_rate_z ** (np.arange(npad_z)+1)).sum() + dz * ncz) + zmax

            # For 2D mesh
            if dimension == 2:
                h = [hx, hz]
                x0_for_mesh = [x0_mesh, z0_mesh]
                self.xyzlim = np.vstack((
                    np.r_[x0, x0+lineLength],
                    np.r_[zmax-corezlength, zmax]
                ))
                fill_value = "extrapolate"

            # For 3D mesh
            else:
                if dy is None:
                    raise Exception("You must input dy (m)")

                self.dy = dy
                self.npad_y = npad_y
                self.pad_rate_y = pad_rate_y

                ylocs = np.unique(self.electrode_locations[:, 1])
                ymin, ymax = ylocs.min(), ylocs.max()
                # 3 cells each for buffer in y-direction
                coreylength = ymax-ymin+dy*6
                ncy = np.round(coreylength/dy)
                hy = [
                    (dy, npad_y, -pad_rate_y),
                    (dy, ncy),
                    (dy, npad_y, pad_rate_y)
                ]
                y0 = ylocs.min()-dy/2.
                y0_mesh = -(
                    (dy * pad_rate_y ** (np.arange(npad_y)+1)).sum()
                    + dy*3 - y0
                )

                h = [hx, hy, hz]
                x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh]
                self.xyzlim = np.vstack((
                    np.r_[x0, x0+lineLength],
                    np.r_[ymin-dy*3, ymax+dy*3],
                    np.r_[zmax-corezlength, zmax]
                ))
                fill_value = np.nan
            mesh = Mesh.TensorMesh(h, x0=x0_for_mesh)
            actind = Utils.surface2ind_topo(mesh, locs, method=method, fill_value=fill_value)
        else:
            raise NotImplementedError()

        return mesh, actind
Esempio n. 17
0
def run(plotIt=True, survey_type="dipole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

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

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

    # Build conductivity and chargeability model
    blk_inds_c = Utils.ModelBuilder.getIndicesSphere(np.r_[60., -25.], 12.5,
                                                     mesh.gridCC)
    blk_inds_r = Utils.ModelBuilder.getIndicesSphere(np.r_[140., -25.], 12.5,
                                                     mesh.gridCC)
    blk_inds_charg = Utils.ModelBuilder.getIndicesSphere(
        np.r_[100., -25], 12.5, mesh.gridCC)
    sigma = np.ones(mesh.nC) * 1. / 100.
    sigma[blk_inds_c] = 1. / 10.
    sigma[blk_inds_r] = 1. / 1000.
    sigma[~actind] = 1. / 1e8
    rho = 1. / sigma
    charg = np.zeros(mesh.nC)
    charg[blk_inds_charg] = 0.1

    # Show the true conductivity model
    if plotIt:
        fig, axs = plt.subplots(2, 1, figsize=(12, 6))
        temp_rho = rho.copy()
        temp_rho[~actind] = np.nan
        temp_charg = charg.copy()
        temp_charg[~actind] = np.nan

        out1 = mesh.plotImage(temp_rho,
                              grid=True,
                              ax=axs[0],
                              gridOpts={'alpha': 0.2},
                              clim=(10, 1000),
                              pcolorOpts={
                                  "cmap": "viridis",
                                  "norm": colors.LogNorm()
                              })
        out2 = mesh.plotImage(temp_charg,
                              grid=True,
                              ax=axs[1],
                              gridOpts={'alpha': 0.2},
                              clim=(0, 0.1),
                              pcolorOpts={"cmap": "magma"})
        for i in range(2):
            axs[i].plot(survey_dc.electrode_locations[:, 0],
                        survey_dc.electrode_locations[:, 1], 'kv')
            axs[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
            axs[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
            axs[i].set_aspect('equal')
        cb = plt.colorbar(out1[0], ax=axs[0])
        cb.set_label("Resistivity (ohm-m)")
        cb = plt.colorbar(out2[0], ax=axs[1])
        cb.set_label("Chargeability")

        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_dc for resistivity
    mtrue_dc = np.log(rho[actind])

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

    # Make synthetic DC data with 5% Gaussian noise
    dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True)
    IO.data_dc = dtrue_dc

    # Generate mtrue_ip for chargability
    mtrue_ip = charg[actind]
    # Generate 2.5D DC problem
    # "N" means potential is defined at nodes
    prb_ip = IP.Problem2D_N(mesh,
                            etaMap=actmap,
                            storeJ=True,
                            rho=rho,
                            Solver=Solver)
    survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="2.5D")
    prb_ip.pair(survey_ip)

    dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05)

    IO.data_ip = dtrue_ip

    # Show apparent resisitivty pseudo-section
    if plotIt:
        IO.plotPseudoSection(data_type='apparent_resistivity',
                             scale='log',
                             cmap='viridis')
        plt.show()

    # Show apparent chargeability pseudo-section
    if plotIt:
        IO.plotPseudoSection(data_type='apparent_chargeability',
                             scale='linear',
                             cmap='magma')
        plt.show()

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure(figsize=(10, 4))
        ax1 = plt.subplot(121)
        out = hist(np.log10(abs(IO.voltages)), bins=20)
        ax1.set_xlabel("log10 DC voltage (V)")
        ax2 = plt.subplot(122)
        out = hist(IO.apparent_resistivity, bins=20)
        ax2.set_xlabel("Apparent Resistivity ($\Omega$m)")
        plt.tight_layout()
        plt.show()

    # Set initial model based upon histogram
    m0_dc = np.ones(actmap.nP) * np.log(100.)
    # Set uncertainty
    # floor
    eps_dc = 10**(-3.2)
    # percentage
    std_dc = 0.05

    mopt_dc, pred_dc = DC.run_inversion(m0_dc,
                                        survey_dc,
                                        actind,
                                        mesh,
                                        std_dc,
                                        eps_dc,
                                        beta0_ratio=1e0,
                                        use_sensitivity_weight=True)

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

    rho_est = mapping * mopt_dc
    rho_est[~actind] = np.nan
    rho_true = rho.copy()
    rho_true[~actind] = 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_dc.electrode_locations[:, 0],
                       survey_dc.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()

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure(figsize=(10, 4))
        ax1 = plt.subplot(121)
        out = hist(np.log10(abs(IO.voltages_ip)), bins=20)
        ax1.set_xlabel("log10 IP voltage (V)")
        ax2 = plt.subplot(122)
        out = hist(IO.apparent_chargeability, bins=20)
        ax2.set_xlabel("Apparent Chargeability (V/V)")
        plt.tight_layout()
        plt.show()

    # Set initial model based upon histogram
    m0_ip = np.ones(actmap.nP) * 1e-10
    # Set uncertainty
    # floor
    eps_ip = 10**(-4)
    # percentage
    std_ip = 0.05
    # Clean sensitivity function formed with true resistivity
    prb_ip._Jmatrix = None
    # Input obtained resistivity to form sensitivity
    prb_ip.rho = mapping * mopt_dc
    mopt_ip, _ = IP.run_inversion(m0_ip,
                                  survey_ip,
                                  actind,
                                  mesh,
                                  std_ip,
                                  eps_ip,
                                  upper=np.Inf,
                                  lower=0.,
                                  beta0_ratio=1e0,
                                  use_sensitivity_weight=True)

    # Convert obtained inversion model to chargeability
    # charg = M(m), where M(.) is a mapping for cells below topography

    charg_est = actmap * mopt_ip
    charg_est[~actind] = np.nan
    charg_true = charg.copy()
    charg_true[~actind] = np.nan

    # show recovered chargeability
    if plotIt:
        fig, ax = plt.subplots(2, 1, figsize=(20, 6))
        out1 = mesh.plotImage(charg_true,
                              clim=(0, 0.1),
                              pcolorOpts={"cmap": "magma"},
                              ax=ax[0])
        out2 = mesh.plotImage(charg_est,
                              clim=(0, 0.1),
                              pcolorOpts={"cmap": "magma"},
                              ax=ax[1])
        out = [out1, out2]
        for i in range(2):
            ax[i].plot(survey_dc.electrode_locations[:, 0],
                       survey_dc.electrode_locations[:, 1], 'rv')
            ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
            ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
            cb = plt.colorbar(out[i][0], ax=ax[i])
            cb.set_label("Resistivity ($\Omega$m)")
            ax[i].set_xlabel("Northing (m)")
            ax[i].set_ylabel("Elevation (m)")
            ax[i].set_aspect('equal')
        plt.tight_layout()
        plt.show()
def run(plotIt=True):

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

    # Create a mesh
    dx = 5.

    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 = 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., 20., 20)
    yr = np.linspace(-20., 20., 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.

    # Create a MAGsurvey
    rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
    rxLoc = PF.BaseMag.RxObs(rxLoc)
    srcField = PF.BaseMag.SrcField([rxLoc], param=H0)
    survey = PF.BaseMag.LinearSurvey(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
    prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv)

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

    # Compute linear forward operator and compute some data
    d = prob.fields(model)

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

    survey.dobs = data
    survey.std = wd
    survey.mtrue = model

    # Create sensitivity weights from our linear forward operator
    rxLoc = survey.srcField.rxList[0].locs
    wr = np.sum(prob.G**2., axis=0)**0.5
    wr = (wr / np.max(wr))

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

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

    # Add directives to the inversion
    opt = Optimization.ProjectedGNCG(maxIter=100,
                                     lower=0.,
                                     upper=1.,
                                     maxIterLS=20,
                                     maxIterCG=20,
                                     tolCG=1e-3)
    invProb = InvProblem.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-4, maxIRLSiter=40)
    saveDict = Directives.SaveOutputEveryIteration(save_txt=False)
    update_Jacobi = Directives.UpdatePreconditioner()
    inv = Inversion.BaseInversion(
        invProb, directiveList=[IRLS, betaest, update_Jacobi, saveDict])

    # Run the inversion
    m0 = np.ones(nC) * 1e-4  # Starting model
    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.PlotUtils.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)
def run(plotIt=True,
        survey_type="dipole-dipole",
        rho_background=1e3,
        rho_block=1e2,
        block_x0=100,
        block_dx=10,
        block_y0=-10,
        block_dy=5):

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

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

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

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

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

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

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

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

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

    # Run inversion
    mopt = inv.run(m0)

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

    rho_est = mapping * mopt
    rho_true = rho.copy()
    # show recovered conductivity
    vmin, vmax = rho.min(), rho.max()
    fig, ax = plt.subplots(2, 1, figsize=(20, 6))
    out1 = mesh.plotImage(rho_true,
                          clim=(10, 1000),
                          pcolorOpts={
                              "cmap": "viridis",
                              "norm": colors.LogNorm()
                          },
                          ax=ax[0])
    out2 = mesh.plotImage(rho_est,
                          clim=(10, 1000),
                          pcolorOpts={
                              "cmap": "viridis",
                              "norm": colors.LogNorm()
                          },
                          ax=ax[1])
    out = [out1, out2]
    for i in range(2):
        ax[i].plot(survey.electrode_locations[:, 0],
                   survey.electrode_locations[:, 1], 'kv')
        ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
        ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
        cb = plt.colorbar(out[i][0], ax=ax[i])
        cb.set_label("Resistivity ($\Omega$m)")
        ax[i].set_xlabel("Northing (m)")
        ax[i].set_ylabel("Elevation (m)")
        ax[i].set_aspect('equal')
    ax[0].set_title("True resistivity model")
    ax[1].set_title("Recovered resistivity model")
    plt.tight_layout()
    plt.show()
Esempio n. 20
0
    #%%    ## TESTING CODE
    # Generate survey using two tiles, compute solution using UBC-DCIP3D
    # and compare by using the pre-computed grid
    padxy = np.r_[dx[1]*expf**(np.asarray(range(npadxy['DC']))+1)]
    padz = np.r_[dx[1]*expf**(np.asarray(range(npadz['DC']))+1)]
    
    hx = np.r_[padxy[::-1], core['DC'], padxy]
    hy = np.r_[padxy[::-1], core['DC'],core['DC'], padxy]
    hz = np.r_[padz[::-1],[33],np.ones(25)*30,[23,18,15,12], np.ones(15)*10,[12,15,18,23],30*expf**(np.asarray(range(npadz['DC'])))]

    mesh = Mesh.TensorMesh([hx,hy,hz], 'CC0')
        
    mesh._x0 = (mesh.x0[0] + np.mean(X[tID]), mesh.x0[1]+np.mean(Y[tID]), mesh.x0[2]-(np.sum(hz[:(npadz['DC']+20)])))
    
    # Extract model from global tolocal mesh
    actv2 = Utils.surface2ind_topo(mesh, topo, 'N')
        
    P = Maps.Mesh2MeshTopo([mesh_global,mesh],[actv,actv2],nIterpPts = 12)  

    model = mesh_global.readModelUBC(work_dir + '\\' + modelfile['DC'])
         
    model_Tile = P*(model[actv])

    m = np.ones(mesh.nC)*1e-8
    m[actv2] = model_Tile
#    mtemp = m.reshape(mesh.vnC, order='F')

    Mesh.TensorMesh.writeUBC(mesh,work_dir +'\\MeshTile.msh')
    Mesh.TensorMesh.writeModelUBC(mesh,work_dir +'\\MeshTile.mod',m)
            
    # Create survey
def run(plotIt=True, survey_type="dipole-dipole", p=0., qx=2., qz=2.):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

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

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

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

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

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

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

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

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

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

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

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

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

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

    # Related to inversion
    reg = Regularization.Sparse(
        mesh, indActive=actind, mapping=regmap,
        gradientType='components'
    )
    #     gradientType = 'components'
    reg.norms = np.c_[p, qx, qz, 0.]
    IRLS = Directives.Update_IRLS(
        maxIRLSiter=20, minGNiter=1,
        betaSearch=False, fix_Jmatrix=True
    )

    opt = Optimization.InexactGaussNewton(maxIter=40)
    invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
    beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2)
    betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0)
    target = Directives.TargetMisfit()
    update_Jacobi = Directives.UpdatePreconditioner()
    inv = Inversion.BaseInversion(
        invProb, directiveList=[
            betaest, IRLS
        ]
        )
    prb.counter = opt.counter = Utils.Counter()
    opt.LSshorten = 0.5
    opt.remember('xc')

    # Run inversion
    mopt = inv.run(m0)

    rho_est = mapping*mopt
    rho_est_l2 = mapping*invProb.l2model
    rho_est[~actind] = np.nan
    rho_est_l2[~actind] = np.nan
    rho_true = rho.copy()
    rho_true[~actind] = np.nan

    # show recovered conductivity
    if plotIt:
        vmin, vmax = rho.min(), rho.max()
        fig, ax = plt.subplots(3, 1, figsize=(20, 9))
        out1 = mesh.plotImage(
                rho_true, clim=(10, 1000),
                pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
                ax=ax[0]
        )
        out2 = mesh.plotImage(
            rho_est_l2, clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
            ax=ax[1]
        )
        out3 = mesh.plotImage(
            rho_est, clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
            ax=ax[2]
        )

        out = [out1, out2, out3]
        titles = ["True", "L2", ("L%d, Lx%d, Lz%d")%(p, qx, qz)]
        for i in range(3):
            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[i].set_title(titles[i])
        plt.tight_layout()
        plt.show()
Esempio n. 22
0
def run(plotIt=True):

    # Create a mesh
    dx = 5.

    hxind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)]
    hyind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)]
    hzind = [(dx, 5, -1.3), (dx, 7), (3.5, 1), (2, 5)]

    mesh = 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(-30., 30., 20)
    yr = np.linspace(-30., 30., 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] + 0.1

    # Create a GRAVsurvey
    rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
    rxLoc = PF.BaseGrav.RxObs(rxLoc)
    srcField = PF.BaseGrav.SrcField([rxLoc])
    survey = PF.BaseGrav.LinearSurvey(srcField)

    # We can now create a density model and generate data
    # Here a simple block in half-space
    model = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz))
    model[(midx-5):(midx-1), (midy-2):(midy+2), -10:-6] = 0.75
    model[(midx+1):(midx+5), (midy-2):(midy+2), -10:-6] = -0.75
    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
    prob = PF.Gravity.GravityIntegral(mesh, rhoMap=idenMap, actInd=actv)

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

    # Compute linear forward operator and compute some data
    d = prob.fields(model)

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

    survey.dobs = data
    survey.std = wd
    survey.mtrue = model

    # Create sensitivity weights from our linear forward operator
    rxLoc = survey.srcField.rxList[0].locs
    wr = np.sum(prob.G**2., axis=0)**0.5
    wr = (wr/np.max(wr))

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

    # Data misfit function
    dmis = DataMisfit.l2_DataMisfit(survey)
    dmis.W = Utils.sdiag(1/wd)

    # Add directives to the inversion
    opt = Optimization.ProjectedGNCG(maxIter=100, lower=-1., upper=1.,
                                     maxIterLS=20, maxIterCG=10,
                                     tolCG=1e-3)
    invProb = InvProblem.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-4, maxIRLSiter=30, coolEpsFact=1.5, beta_tol=1e-1,
    )
    saveDict = Directives.SaveOutputEveryIteration(save_txt=False)
    update_Jacobi = Directives.UpdatePreconditioner()
    inv = Inversion.BaseInversion(
        invProb, directiveList=[IRLS, betaest, update_Jacobi, saveDict]
    )

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

    if plotIt:
        # Here is the recovered susceptibility model
        ypanel = midx
        zpanel = -7
        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

        vmin, vmax = mrec.min(), mrec.max()

        # Plot the data
        Utils.PlotUtils.plot2Ddata(rxLoc, data)

        plt.figure()

        # Plot L2 model
        ax = plt.subplot(321)
        mesh.plotSlice(m_l2, ax=ax, normal='Z', ind=zpanel,
                       grid=True, clim=(vmin, vmax))
        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')

        # Vertical section
        ax = plt.subplot(322)
        mesh.plotSlice(m_l2, ax=ax, normal='Y', ind=midx,
                       grid=True, clim=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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, np.max(saveDict.phi_d)/2.,
            '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)
Esempio n. 23
0
File: fm3d.py Progetto: JKutt/PyDev
def run(plotIt=True, survey_type="pole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

    fileName1 = "/Users/juan/Documents/testData/fmdata-daf.con"  # output mod
    fileName2 = "/Users/juan/Documents/testData/forwardmodel.msh"  # input mesh
    mesh = Mesh.TensorMesh._readUBC_3DMesh(fileName2)  # Read in/create mesh

    print("Starting forward modeling")
    start = clock()
    # Define model Background
    rx = getRxData()  # rx locations
    tx = getTxData()  # tx locations
    survey_dc = generateSurvey(rx, tx, 45, 55)  # create survey object
    survey_dc.survey_type = "pole-dipole"
    survey_dc.getABMN_locations()  # get locations
    # survey_dc = IO.from_ambn_locations_to_survey(
    #     survey_dc.a_locations, survey_dc.b_locations,
    #     survey_dc.m_locations, survey_dc.n_locations,
    #     survey_type, data_dc_type='volt', data_ip_type='volt'
    # )
    uniq = Utils.uniqueRows(
        np.vstack((survey_dc.a_locations, survey_dc.b_locations,
                   survey_dc.m_locations, survey_dc.n_locations)))
    electrode_locations = uniq[0]  # assign
    actinds = Utils.surface2ind_topo(mesh, electrode_locations,
                                     method='cubic')  # active indicies
    # survey_dc.drapeTopo(mesh, actinds)
    IO.a_locations = survey_dc.a_locations.copy()
    IO.b_locations = survey_dc.b_locations.copy()
    IO.m_locations = survey_dc.m_locations.copy()
    IO.n_locations = survey_dc.n_locations.copy()  # drape topo
    IO.data_dc_type = 'volt'
    IO.G = IO.geometric_factor(survey_dc)
    # =============================================================================
    # create sphere for ice representation
    x0 = (np.max(mesh.gridCC[:, 0]) +
          np.min(mesh.gridCC[:, 0])) / 2. + 50  # x0 center point of sphere
    y0 = (np.max(mesh.gridCC[:, 1]) +
          np.min(mesh.gridCC[:, 1])) / 2. - 50  # y0 center point of sphere
    z0 = 2350  # x0 center point of sphere
    # (np.max(mesh.gridCC[:, 2]) + np.min(mesh.gridCC[:, 2])) / 2.
    r0 = 500  # radius of sphere
    print(x0, y0, z0)
    csph = (np.sqrt((mesh.gridCC[:, 0] - x0)**2. +
                    (mesh.gridCC[:, 1] - y0)**2. +
                    (mesh.gridCC[:, 2] - z0)**2.)) < r0  # indicies of sphere
    # sphere done =================================================================
    # ============================================================================
    # Create model
    mx = np.ones(mesh.nC) * 0.018  # chargeability
    sigma = np.ones(mesh.nC) * 1. / 15000.

    # create dipping structure parameters
    theta = 45. * np.pi / 180.  # dipping angle
    x0_d = 374700.
    x1_d = 375000.
    y0_d = 6275850.
    y0_1d = 900. * np.sin(theta) + y0_d
    y1_d = 6275900.
    y1_1d = 900. * np.sin(theta) + y1_d
    z0_d = 1900.
    z1_d = z0_d - (900. * np.cos(theta))
    m_ = (z0_d - z1_d) / (y0_1d - y0_d)  # slope of dip

    # loop through mesh and assign dipping structure conductivity
    for idx in range(mesh.nC):
        if z1_d <= mesh.gridCC[idx, 2] <= z0_d:
            if (x0_d <= mesh.gridCC[idx, 0] <= x1_d):
                yslope1 = y0_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d)
                yslope2 = y1_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d)
                if yslope1 <= mesh.gridCC[idx, 1] <= yslope2:
                    mx[idx] = 0.035
                    sigma[idx] = 1. / 300.

    # mx[csph] = ((0.025) *
    #             np.ones_like(mx[csph]))             # set sphere values
    mx[~actinds] = 1. / 1e8  # flag air values
    # sigma[csph] = ((5000.) *
    #                np.ones_like(sigma[csph]))             # set sphere values
    sigma[~actinds] = 1. / 1e8  # flag air values
    rho = 1. / sigma
    stop = clock()
    print(stop)
    # plot results
    # Show the true conductivity model
    if plotIt:
        ncy = mesh.nCy
        ncz = mesh.nCz
        ncx = mesh.nCx
        print(mesh.nC)
        clim = [0, 0.04]
        fig, ax = plt.subplots(2, 2, figsize=(12, 6))
        ax = Utils.mkvc(ax)
        dat = mesh.plotSlice(((mx)),
                             ax=ax[0],
                             normal='Z',
                             clim=clim,
                             ind=int(ncz / 2 - 14),
                             pcolorOpts={"cmap": "jet"})
        ax[0].plot(rx[:, 0], rx[:, 1], 'or')
        ax[0].plot(tx[:, 0], tx[:, 1], 'dk')
        mesh.plotSlice(((mx)),
                       ax=ax[1],
                       normal='Y',
                       clim=clim,
                       ind=int(ncy / 2 + 2),
                       pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mx)),
                       ax=ax[2],
                       normal='X',
                       clim=clim,
                       ind=int(ncx / 2 + 4),
                       pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mx)),
                       ax=ax[3],
                       normal='X',
                       clim=clim,
                       ind=int(ncx / 2 + 8),
                       pcolorOpts={"cmap": "jet"})
        cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7])
        cb = plt.colorbar(dat[0], ax=cbar_ax)
        fig.subplots_adjust(right=0.85)
        cb.set_label('V/V')
        cbar_ax.axis('off')
        plt.show()
        # print(mtrue.min(), mtrue.max())
        # clim = [0, 20000]
        # fig, ax = plt.subplots(2, 2, figsize=(12, 6))
        # ax = Utils.mkvc(ax)
        # dat = mesh.plotSlice(((mtrue)), ax=ax[0], normal='Z', clim=clim,
        #                      ind=int(ncz / 2 - 4), pcolorOpts={"cmap": "jet"})
        # ax[0].plot(rx[:, 0], rx[:, 1], 'or')
        # mesh.plotSlice(((mtrue)), ax=ax[1], normal='Y', clim=clim,
        #                ind=int(ncy / 2), pcolorOpts={"cmap": "jet"})
        # mesh.plotSlice(((mtrue)), ax=ax[2], normal='X', clim=clim,
        #                ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"})
        # mesh.plotSlice(((mtrue)), ax=ax[3], normal='X', clim=clim,
        #                ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"})
        # cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7])
        # cb = plt.colorbar(dat[0], ax=cbar_ax)
        # fig.subplots_adjust(right=0.85)
        # cb.set_label('rho')
        # cbar_ax.axis('off')
        # plt.show()

    # print(error.size, survey_ip.obs.size)
    # error = np.asarray(survey_ip.dobs) * (np.random.randint(-1, 2, survey_ip.dobs) / 20.)
    # survey_ip.dobs = survey_ip.dobs + error
    # Use Exponential Map: m = log(rho)
    actmap = Maps.InjectActiveCells(mesh,
                                    indActive=actinds,
                                    valInactive=np.log(1e8))
    mapping = Maps.ExpMap(mesh) * actmap

    # Generate mtrue_dc for resistivity
    mtrue_dc = np.log(rho[actinds])

    # Generate 3D DC problem
    # "CC" means potential is defined at center
    prb = DC.Problem3D_CC(mesh, rhoMap=mapping, storeJ=False, Solver=Solver)
    # Pair problem with survey
    # try:
    prb.pair(survey_dc)
    # except:
    #     survey_dc.unpair()
    #     prb.pair(survey_dc)

    survey_dc.dpred(mtrue_dc)
    # Make synthetic DC data with 5% Gaussian noise
    dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True)
    IO.data_dc = dtrue_dc
    # Generate mtrue_ip for chargability
    mtrue_ip = mx[actinds]
    # Generate 3D DC problem
    # "CC" means potential is defined at center
    prb_ip = IP.Problem3D_CC(mesh,
                             etaMap=actmap,
                             storeJ=False,
                             rho=rho,
                             Solver=Solver)
    survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="3D")
    survey_ip.survey_type = "pole-dipole"
    survey_ip.getABMN_locations()
    prb_ip.pair(survey_ip)
    survey_ip.dpred(mtrue_ip)
    dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05)
    survey_ip.std = np.ones_like(dtrue_ip) * 0.05
    survey_ip.eps = np.ones_like(dtrue_ip) * 10**(-4)
    IO.data_ip = dtrue_ip
    DC.Utils.writeUBC_DCobs("fmip.obs", survey_ip, 3, 'GENERAL', 'pole-dipole')
Esempio n. 24
0
def run(plotIt=True, survey_type="dipole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

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

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

    # Build conductivity and chargeability model
    blk_inds_c = Utils.ModelBuilder.getIndicesSphere(
        np.r_[60., -25.], 12.5, mesh.gridCC
    )
    blk_inds_r = Utils.ModelBuilder.getIndicesSphere(
        np.r_[140., -25.], 12.5, mesh.gridCC
    )
    blk_inds_charg = Utils.ModelBuilder.getIndicesSphere(
        np.r_[100., -25], 12.5, mesh.gridCC
    )
    sigma = np.ones(mesh.nC)*1./100.
    sigma[blk_inds_c] = 1./10.
    sigma[blk_inds_r] = 1./1000.
    sigma[~actind] = 1./1e8
    rho = 1./sigma
    charg = np.zeros(mesh.nC)
    charg[blk_inds_charg] = 0.1

    # Show the true conductivity model
    if plotIt:
        fig, axs = plt.subplots(2,1, figsize=(12, 6))
        temp_rho = rho.copy()
        temp_rho[~actind] = np.nan
        temp_charg = charg.copy()
        temp_charg[~actind] = np.nan

        out1 = mesh.plotImage(
            temp_rho, grid=True, ax=axs[0], gridOpts={'alpha': 0.2},
            clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()}
        )
        out2 = mesh.plotImage(
            temp_charg, grid=True, ax=axs[1], gridOpts={'alpha': 0.2},
            clim=(0, 0.1),
            pcolorOpts={"cmap": "magma"}
        )
        for i in range(2):
            axs[i].plot(
                survey_dc.electrode_locations[:, 0],
                survey_dc.electrode_locations[:, 1], 'kv'
            )
            axs[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
            axs[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
            axs[i].set_aspect('equal')
        cb = plt.colorbar(out1[0], ax=axs[0])
        cb.set_label("Resistivity (ohm-m)")
        cb = plt.colorbar(out2[0], ax=axs[1])
        cb.set_label("Chargeability")

        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_dc for resistivity
    mtrue_dc = np.log(rho[actind])

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

    # Make synthetic DC data with 5% Gaussian noise
    dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True)
    IO.data_dc = dtrue_dc

    # Generate mtrue_ip for chargability
    mtrue_ip = charg[actind]
    # Generate 2.5D DC problem
    # "N" means potential is defined at nodes
    prb_ip = IP.Problem2D_N(
        mesh, etaMap=actmap, storeJ=True, rho=rho,
        Solver=Solver
    )
    survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="2.5D")
    prb_ip.pair(survey_ip)
    dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05)

    IO.data_ip = dtrue_ip

    # Show apparent resisitivty pseudo-section
    if plotIt:
        IO.plotPseudoSection(
            data_type='apparent_resistivity', scale='log',
            cmap='viridis'
        )
        plt.show()

    # Show apparent chargeability pseudo-section
    if plotIt:
        IO.plotPseudoSection(
            data_type='apparent_chargeability', scale='linear',
            cmap='magma'
        )
        plt.show()

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure(figsize=(10, 4))
        ax1 = plt.subplot(121)
        out = hist(np.log10(abs(IO.voltages)), bins=20)
        ax1.set_xlabel("log10 DC voltage (V)")
        ax2 = plt.subplot(122)
        out = hist(IO.apparent_resistivity, bins=20)
        ax2.set_xlabel("Apparent Resistivity ($\Omega$m)")
        plt.tight_layout()
        plt.show()

    # Set initial model based upon histogram
    m0_dc = np.ones(actmap.nP)*np.log(100.)
    # Set uncertainty
    # floor
    eps_dc = 10**(-3.2)
    # percentage
    std_dc = 0.05

    mopt_dc, pred_dc = DC.run_inversion(
        m0_dc, survey_dc, actind, mesh, std_dc, eps_dc,
        beta0_ratio=1e0,
        use_sensitivity_weight=True
        )

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

    rho_est = mapping*mopt_dc
    rho_est[~actind] = np.nan
    rho_true = rho.copy()
    rho_true[~actind] = 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_dc.electrode_locations[:, 0],
                survey_dc.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()

    # Show apparent resisitivty histogram
    if plotIt:
        fig = plt.figure(figsize=(10, 4))
        ax1 = plt.subplot(121)
        out = hist(np.log10(abs(IO.voltages_ip)), bins=20)
        ax1.set_xlabel("log10 IP voltage (V)")
        ax2 = plt.subplot(122)
        out = hist(IO.apparent_chargeability, bins=20)
        ax2.set_xlabel("Apparent Chargeability (V/V)")
        plt.tight_layout()
        plt.show()


    # Set initial model based upon histogram
    m0_ip = np.ones(actmap.nP)*1e-10
    # Set uncertainty
    # floor
    eps_ip = 10**(-4)
    # percentage
    std_ip = 0.05
    # Clean sensitivity function formed with true resistivity
    prb_ip._Jmatrix = None
    # Input obtained resistivity to form sensitivity
    prb_ip.rho = mapping*mopt_dc
    mopt_ip, _ = IP.run_inversion(
        m0_ip, survey_ip, actind, mesh, std_ip, eps_ip,
        upper=np.Inf, lower=0.,
        beta0_ratio=1e0,
        use_sensitivity_weight=True
    )

    # Convert obtained inversion model to chargeability
    # charg = M(m), where M(.) is a mapping for cells below topography

    charg_est = actmap*mopt_ip
    charg_est[~actind] = np.nan
    charg_true = charg.copy()
    charg_true[~actind] = np.nan

    # show recovered chargeability
    if plotIt:
        fig, ax = plt.subplots(2, 1, figsize=(20, 6))
        out1 = mesh.plotImage(
                charg_true, clim=(0, 0.1),
                pcolorOpts={"cmap": "magma"},
                ax=ax[0]
        )
        out2 = mesh.plotImage(
            charg_est, clim=(0, 0.1),
            pcolorOpts={"cmap": "magma"},
            ax=ax[1]
        )
        out = [out1, out2]
        for i in range(2):
            ax[i].plot(
                survey_dc.electrode_locations[:, 0],
                survey_dc.electrode_locations[:, 1], 'rv'
            )
            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()
Esempio n. 25
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., 90., 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., 200., 50),
                               np.linspace(-200., 200., 50))

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

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

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

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

        # 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.ModelBuilder.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
        prob = PF.Magnetics.MagneticIntegral(self.mesh,
                                             chiMap=idenMap,
                                             actInd=actv)

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

        # Compute linear forward operator and compute some data
        data = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        noise = np.random.randn(len(data))
        data += noise
        wd = np.ones(len(data)) * 1.

        survey.dobs = data
        survey.std = wd

        # Create sensitivity weights from our linear forward operator
        rxLoc = survey.srcField.rxList[0].locs
        wr = prob.getJtJdiag(self.model)**0.5
        wr /= np.max(wr)

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

        reg.mref = np.zeros(nC)

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

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

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+6)

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

        # saveOuput = Directives.SaveOutputEveryIteration()
        # saveModel.fileName = work_dir + out_dir + 'ModelSus'
        self.inv = Inversion.BaseInversion(invProb,
                                           directiveList=[IRLS, update_Jacobi])
def run(plotIt=True, survey_type="dipole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # Run inversion
    mopt = inv.run(m0)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                zOffset += dx

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # Pre-conditioner
        update_Jacobi = Directives.UpdatePreconditioner()

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.inv = Inversion.BaseInversion(
            invProb,
            directiveList=[
                ProjSpherical, IRLS, update_SensWeight, update_Jacobi
            ]
        )
Esempio n. 28
0
            if topo is not None:
                meshLocal = meshutils.refine_tree_xyz(
                    meshLocal, topo, method='surface',
                    octree_levels=octree_levels_topo, finalize=False
                )

            meshLocal = meshutils.refine_tree_xyz(
                meshLocal, topo_elevations_at_data_locs[ind_t, :],
                method='surface',
                max_distance=max_distance,
                octree_levels=octree_levels_obs,
                octree_levels_padding=octree_levels_padding,
                finalize=True,
            )

        tileLayer = Utils.surface2ind_topo(meshLocal, topo)

        # Calculate approximate problem size
        nDt, nCt = ind_t.sum()*1. * len(survey.components), tileLayer.sum()*1.

        nChunks = n_cpu  # Number of chunks
        cSa, cSb = int(nDt/nChunks), int(nCt/nChunks)  # Chunk sizes
        usedRAM = nDt * nCt * 8. * 1e-9
        count += 1
        print(nDt, nCt, usedRAM, binCount.min())
        del meshLocal

    nTiles = X1.shape[0]

    # Loop through the tiles and generate all sensitivities
    print("Number of tiles:" + str(nTiles))
Esempio n. 29
0
if topo is not None:
    mesh = meshutils.refine_tree_xyz(mesh,
                                     topo,
                                     method='surface',
                                     octree_levels=octreeTopo,
                                     finalize=False)

mesh = meshutils.refine_tree_xyz(mesh,
                                 newTopo,
                                 method='surface',
                                 octree_levels=octreeObs,
                                 octree_levels_padding=octree_levels_padding,
                                 finalize=True)

# Compute active cells
activeCells = Utils.surface2ind_topo(mesh, topo, gridLoc='CC')

#    activeCells = meshutils.activeTopoLayer(mesh, topo)

Mesh.TreeMesh.writeUBC(
    mesh,
    workDir + dsep + outDir + 'OctreeMeshGlobal.msh',
    models={workDir + dsep + outDir + 'ActiveSurface.act': activeCells})

# Get the layer of cells directly below topo
#activeCells = Utils.actIndFull2layer(mesh, active)
nC = int(activeCells.sum())  # Number of active cells
print(nC)
# Create active map to go from reduce set to full
activeCellsMap = Maps.InjectActiveCells(mesh, activeCells, ndv)
def run(
    plotIt=True, survey_type="dipole-dipole",
    rho_background=1e3,
    rho_block=1e2,
    block_x0=100,
    block_dx=10,
    block_y0=-10,
    block_dy=5
):

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

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

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

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

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

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

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

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

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

    # Run inversion
    mopt = inv.run(m0)

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

    rho_est = mapping*mopt
    rho_true = rho.copy()
    # show recovered conductivity
    vmin, vmax = rho.min(), rho.max()
    fig, ax = plt.subplots(2, 1, figsize=(20, 6))
    out1 = mesh.plotImage(
            rho_true, clim=(10, 1000),
            pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
            ax=ax[0]
    )
    out2 = mesh.plotImage(
        rho_est, clim=(10, 1000),
        pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()},
        ax=ax[1]
    )
    out = [out1, out2]
    for i in range(2):
        ax[i].plot(
            survey.electrode_locations[:, 0],
            survey.electrode_locations[:, 1], 'kv'
        )
        ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max())
        ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min())
        cb = plt.colorbar(out[i][0], ax=ax[i])
        cb.set_label("Resistivity ($\Omega$m)")
        ax[i].set_xlabel("Northing (m)")
        ax[i].set_ylabel("Elevation (m)")
        ax[i].set_aspect('equal')
    ax[0].set_title("True resistivity model")
    ax[1].set_title("Recovered resistivity model")
    plt.tight_layout()
    plt.show()
Esempio n. 31
0
    def set_mesh(self, topo=None,
                dx=None, dy=None, dz=None,
                n_spacing=None, corezlength=None,
                npad_x=7, npad_y=7, npad_z=7,
                pad_rate_x=1.3, pad_rate_y=1.3, pad_rate_z=1.3,
                ncell_per_dipole=4, mesh_type='TensorMesh',
                dimension=2,
                method='nearest'
                ):
        """
        Set up a mesh for a given DC survey
        """
        if mesh_type == 'TreeMesh':
            raise NotImplementedError()

        # 2D or 3D mesh
        if dimension in [2, 3]:
            if dimension == 2:
                z_ind = 1
            else:
                z_ind = 2
            a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min()
            lineLength = abs(
                self.electrode_locations[:, 0].max() -
                self.electrode_locations[:, 0].min()
            )
            dx_ideal = a/ncell_per_dipole
            if dx is None:
                dx = dx_ideal
                warnings.warn(
                    "dx is set to {} m (samllest electrode spacing ({}) / {})".format(dx, a, ncell_per_dipole)
                )
            if dz is None:
                dz = dx*0.5
                warnings.warn(
                    "dz ({} m) is set to dx ({} m) / {}".format(dz, dx, 2)
                )
            x0 = self.electrode_locations[:, 0].min()
            if topo is None:
                locs = self.electrode_locations
            else:
                locs = np.vstack((topo, self.electrode_locations))

            if dx > dx_ideal:
                # warnings.warn(
                #     "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a)
                # )
                pass
            self.dx = dx
            self.dz = dz
            self.npad_x = npad_x
            self.npad_z = npad_z
            self.pad_rate_x = pad_rate_x
            self.pad_rate_z = pad_rate_z
            self.ncell_per_dipole = ncell_per_dipole
            zmax = locs[:, z_ind].max()
            zmin = locs[:, z_ind].min()

            # 3 cells each for buffer
            corexlength = lineLength + dx * 6
            if corezlength is None:
                corezlength = self.grids[:, z_ind].max()

            ncx = np.round(corexlength/dx)
            ncz = np.round(corezlength/dz)
            hx = [
                (dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x)
            ]
            hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)]
            x0_mesh = -(
                (dx * pad_rate_x ** (np.arange(npad_x)+1)).sum() + dx * 3 - x0
            )
            z0_mesh = -((dz * pad_rate_z ** (np.arange(npad_z)+1)).sum() + dz * ncz) + zmax

            # For 2D mesh
            if dimension == 2:
                h = [hx, hz]
                x0_for_mesh = [x0_mesh, z0_mesh]
                self.xyzlim = np.vstack((
                    np.r_[x0, x0+lineLength],
                    np.r_[zmax-corezlength, zmax]
                ))

            # For 3D mesh
            else:
                if dy is None:
                    raise Exception("You must input dy (m)")

                self.dy = dy
                self.npad_y = npad_y
                self.pad_rate_y = pad_rate_y

                ylocs = np.unique(self.electrode_locations[:, 1])
                ymin, ymax = ylocs.min(), ylocs.max()
                # 3 cells each for buffer in y-direction
                coreylength = ymax-ymin+dy*6
                ncy = np.round(coreylength/dy)
                hy = [
                    (dy, npad_y, -pad_rate_y),
                    (dy, ncy),
                    (dy, npad_y, pad_rate_y)
                ]
                y0 = ylocs.min()-dy/2.
                y0_mesh = -(
                    (dy * pad_rate_y ** (np.arange(npad_y)+1)).sum()
                    + dy*3 - y0
                )

                h = [hx, hy, hz]
                x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh]
                self.xyzlim = np.vstack((
                    np.r_[x0, x0+lineLength],
                    np.r_[ymin-dy*3, ymax+dy*3],
                    np.r_[zmax-corezlength, zmax]
                ))
            mesh = Mesh.TensorMesh(h, x0=x0_for_mesh)
            actind = Utils.surface2ind_topo(mesh, locs, method=method)
        else:
            raise NotImplementedError()

        return mesh, actind
Esempio n. 32
0
def run(plotIt=True):

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

    # Create a mesh
    dx = 5.

    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 = 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 actv cells
    actv = Utils.surface2ind_topo(mesh, topo, 'N')
    actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem],
                      dtype=int) - 1

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

    # Create and array of observation points
    xr = np.linspace(-20., 20., 20)
    yr = np.linspace(-20., 20., 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.

    # Create a MAGsurvey
    rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
    rxLoc = PF.BaseMag.RxObs(rxLoc)
    srcField = PF.BaseMag.SrcField([rxLoc], param=H0)
    survey = PF.BaseMag.LinearSurvey(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)

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

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

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

    # Compute linear forward operator and compute some data
    d = prob.fields(model)

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

    survey.dobs = data
    survey.std = wd
    survey.mtrue = model

    # Create sensitivity weights from our linear forward operator
    rxLoc = survey.srcField.rxList[0].locs
    wr = np.sum(prob.G**2., axis=0)**0.5
    wr = (wr/np.max(wr))

    # Create a regularization
    reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
    reg.cell_weights = wr
    reg.norms = [0, 1, 1, 1]
    reg.eps_p, reg.eps_q = 1e-3, 1e-3

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

    # Add directives to the inversion
    opt = Optimization.ProjectedGNCG(maxIter=100, lower=0., upper=1.,
                                     maxIterLS=20, maxIterCG=10, tolCG=1e-3)
    invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
    betaest = Directives.BetaEstimate_ByEig()

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

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

    if plotIt:
        # Here is the recovered susceptibility model
        ypanel = midx
        zpanel = -5
        m_l2 = actvMap * IRLS.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
        PF.Magnetics.plot_obs_2D(rxLoc, d=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')
Esempio n. 33
0
### make a mesh
mesh = Mesh.TensorMesh([hx_ind, hy_ind, hz_ind], 'CCC')

# Get index of the center
mid_x = int(mesh.nCx/2)
mid_y = 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
active_cells = Utils.surface2ind_topo(mesh, topo, 'N')
active_cells = np.where(active_cells)[0]
num_cells = len(active_cells)

### Create and array of observation points
x_receiver = np.linspace(-30., 30., 20)
y_receiver = np.linspace(-30., 30., 20)
X_r, Y_r = np.meshgrid(x_receiver, y_receiver)

### Move the observation points 5m (?) above the topo
Z_r = -np.exp((X_r**2 + Y_r**2) / 75**2) + mesh.vectorNz[-1] + 0.001

### Create a GRAVsurvey
### make an array of station locations
rx_loc = np.c_[Utils.mkvc(X_r.T), Utils.mkvc(Y_r.T), Utils.mkvc(Z_r.T)]
Esempio n. 34
0
def run(plotIt=True):

    H0 = (50000., 90., 0.)

    # Create a mesh
    dx = 5.

    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 = Mesh.TensorMesh([hxind, hyind, hzind], 'CCC')

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

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

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

    # Create and array of observation points
    xr = np.linspace(-20., 20., 20)
    yr = np.linspace(-20., 20., 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.

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

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

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

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

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


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

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

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

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

    # Compute linear forward operator and compute some data
    d = prob.fields(model)

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

    survey.dobs = data
    survey.std = wd
    survey.mtrue = model

    # Plot the data
    rxLoc = survey.srcField.rxList[0].locs

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

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

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

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

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

    # Make depth weighting
    wr = np.zeros(sumMap.shape[1])

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

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

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

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

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

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

    reg = reg_m1 + reg_m2

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

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

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

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

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

        mesh.plot_3d_slicer(actvMap * sumMap * mrecSum, aspect="equal", zslice=30, pcolorOpts={"cmap":'inferno_r'}, transparent='slider')
Esempio n. 35
0
    def setUp(self):

        np.random.seed(0)

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

        # Create a mesh
        dx = 5.

        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)]

        mesh = 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]

        # Go from topo to actv cells
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]
        actv = Utils.surface2ind_topo(mesh, topo, 'N')
        actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem],
                          dtype=int) - 1

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

        # Create and array of observation points
        xr = np.linspace(-20., 20., 20)
        yr = np.linspace(-20., 20., 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.

        # Create a MAGsurvey
        rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        rxLoc = PF.BaseMag.RxObs(rxLoc)
        srcField = PF.BaseMag.SrcField([rxLoc], param=H0)
        survey = PF.BaseMag.LinearSurvey(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)
        self.model = model[actv]

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

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

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

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

        # Compute linear forward operator and compute some data
        d = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        data = d + np.random.randn(len(d))
        wd = np.ones(len(data)) * 1.

        survey.dobs = data
        survey.std = wd

        # Create sensitivity weights from our linear forward operator
        wr = np.sum(prob.G**2., axis=0)**0.5
        wr = (wr / np.max(wr))

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

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

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

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
        betaest = Directives.BetaEstimate_ByEig()

        # Here is where the norms are applied
        IRLS = Directives.Update_IRLS(f_min_change=1e-4, minGNiter=1)
        update_Jacobi = Directives.UpdatePreconditioner()
        self.inv = Inversion.BaseInversion(
            invProb, directiveList=[IRLS, betaest, update_Jacobi])
def run(plotIt=True, survey_type="dipole-dipole", p=0., qx=2., qz=2.):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

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

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

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

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

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

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

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

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

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

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

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

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

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

    # Related to inversion
    reg = Regularization.Sparse(mesh,
                                indActive=actind,
                                mapping=regmap,
                                gradientType='components')
    #     gradientType = 'components'
    reg.norms = np.c_[p, qx, qz, 0.]
    IRLS = Directives.Update_IRLS(maxIRLSiter=20,
                                  minGNiter=1,
                                  betaSearch=False,
                                  fix_Jmatrix=True)

    opt = Optimization.InexactGaussNewton(maxIter=40)
    invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
    beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2)
    betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0)
    target = Directives.TargetMisfit()
    update_Jacobi = Directives.UpdatePreconditioner()
    inv = Inversion.BaseInversion(invProb, directiveList=[betaest, IRLS])
    prb.counter = opt.counter = Utils.Counter()
    opt.LSshorten = 0.5
    opt.remember('xc')

    # Run inversion
    mopt = inv.run(m0)

    rho_est = mapping * mopt
    rho_est_l2 = mapping * invProb.l2model
    rho_est[~actind] = np.nan
    rho_est_l2[~actind] = np.nan
    rho_true = rho.copy()
    rho_true[~actind] = np.nan

    # show recovered conductivity
    if plotIt:
        vmin, vmax = rho.min(), rho.max()
        fig, ax = plt.subplots(3, 1, figsize=(20, 9))
        out1 = mesh.plotImage(rho_true,
                              clim=(10, 1000),
                              pcolorOpts={
                                  "cmap": "viridis",
                                  "norm": colors.LogNorm()
                              },
                              ax=ax[0])
        out2 = mesh.plotImage(rho_est_l2,
                              clim=(10, 1000),
                              pcolorOpts={
                                  "cmap": "viridis",
                                  "norm": colors.LogNorm()
                              },
                              ax=ax[1])
        out3 = mesh.plotImage(rho_est,
                              clim=(10, 1000),
                              pcolorOpts={
                                  "cmap": "viridis",
                                  "norm": colors.LogNorm()
                              },
                              ax=ax[2])

        out = [out1, out2, out3]
        titles = ["True", "L2", ("L%d, Lx%d, Lz%d") % (p, qx, qz)]
        for i in range(3):
            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[i].set_title(titles[i])
        plt.tight_layout()
        plt.show()
    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., 90., 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., 200., 50),
            np.linspace(-200., 200., 50)
        )

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

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

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

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

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

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

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

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

        # Number of cells at the small octree level
        # For now equal in 3D

        nCx, nCy, nCz = 2**(maxLevel), 2**(maxLevel), 2**(maxLevel)
        # nCy = 2**(int(np.log2(extent/h[1]))+1)
        # nCz = 2**(int(np.log2(extent/h[2]))+1)

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

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

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

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

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

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

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

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

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

                zOffset += dx

        self.mesh.finalize()
        # 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.ModelBuilder.addBlock(
            self.mesh.gridCC, np.zeros(self.mesh.nC),
            np.r_[-20, -20, -5], np.r_[20, 20, 30], 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
        prob = PF.Magnetics.MagneticIntegral(
            self.mesh, chiMap=idenMap, actInd=actv
        )

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

        # Compute linear forward operator and compute some data
        data = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        noise = np.random.randn(len(data))
        data += noise
        wd = np.ones(len(data))*1.

        survey.dobs = data
        survey.std = wd

        # Create sensitivity weights from our linear forward operator
        rxLoc = survey.srcField.rxList[0].locs
        wr = np.zeros(prob.G.shape[1])
        for ii in range(survey.nD):
            wr += (prob.G[ii, :]/survey.std[ii])**2.

        # wr = (wr/np.max(wr))
        wr = wr**0.5

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

        reg.mref = np.zeros(nC)

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

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

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+4)

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

        # saveOuput = Directives.SaveOutputEveryIteration()
        # saveModel.fileName = work_dir + out_dir + 'ModelSus'
        self.inv = Inversion.BaseInversion(
            invProb,
            directiveList=[IRLS, update_Jacobi]
        )
Esempio n. 38
0
                (mesh.gridCC[:, 2] - z0)**2.)) < r0  # indicies of sphere
# sphere done =================================================================

print("Starting forward modeling")
start = clock()
# Define model Background
ln_sigback = 0.023  # chargeability
rx = getRxData()  # rx locations
tx = getTxData()  # tx locations
survey = generateSurvey(rx, tx, 45, 65)  # create survey object
survey.getABMN_locations()  # get locations
uniq = Utils.uniqueRows(
    np.vstack((survey.a_locations, survey.b_locations, survey.m_locations,
               survey.n_locations)))  # row the locations
electrode_locations = uniq[0]  # assign
actinds = Utils.surface2ind_topo(mesh, electrode_locations,
                                 method='cubic')  # active indicies
survey.drapeTopo(mesh, actinds)  # drape topo
# ============================================================================
# Create model
mx = np.ones(mesh.nC) * 0.015  # chargeability
sigma = np.ones(mesh.nC) * 1. / 33000.

# create dipping structure parameters
theta = 45. * np.pi / 180.  # dipping angle
x0_d = 374700.
x1_d = 375000.
y0_d = 6275850.
y0_1d = 500. * np.sin(theta) + y0_d
y1_d = 6275900.
y1_1d = 500. * np.sin(theta) + y1_d
z0_d = 1860.
Esempio n. 39
0
File: fm3d.py Progetto: JKutt/PyDev
def run(plotIt=True, survey_type="pole-dipole"):
    np.random.seed(1)
    # Initiate I/O class for DC
    IO = DC.IO()
    # Obtain ABMN locations

    fileName1 = "C:/Users/johnk/Projects/Seabridge/fmdataDC.con"   # output mod
    fileName1_ = "C:/Users/johnk/Projects/Seabridge/fmdataIP.chg"  # output mod
    fileName2 = "C:/Users/johnk/Projects/Seabridge/forwardmodel.msh"  # in mesh
    mesh = Mesh.TensorMesh._readUBC_3DMesh(fileName2)     # Read in/create mesh

    print("Starting forward modeling")
    start = clock()
    # Define model Background
    rx = getRxData()                                     # rx locations
    tx = getTxData()                                     # tx locations
    survey_dc = generateSurvey(rx, tx, 45, 65)         # create survey object
    survey_dc.getABMN_locations()                           # get locations
    # survey_dc = IO.from_ambn_locations_to_survey(
    #     survey_dc.a_locations, survey_dc.b_locations,
    #     survey_dc.m_locations, survey_dc.n_locations,
    #     survey_type, data_dc_type='volt', data_ip_type='volt'
    # )
    uniq = Utils.uniqueRows(np.vstack((survey_dc.a_locations,
                                       survey_dc.b_locations,
                                       survey_dc.m_locations,
                                       survey_dc.n_locations)))
    electrode_locations = uniq[0]                            # assign
    actinds = Utils.surface2ind_topo(mesh,
                                     electrode_locations,
                                     method='cubic')      # active indicies
    survey_dc.drapeTopo(mesh, actinds)                       # drape topo
# =============================================================================
    # create sphere for ice representation
    x0 = (np.max(mesh.gridCC[:, 0]) +
          np.min(mesh.gridCC[:, 0])) / 2. + 50      # x0 center point of sphere
    y0 = (np.max(mesh.gridCC[:, 1]) +
          np.min(mesh.gridCC[:, 1])) / 2. - 50      # y0 center point of sphere
    z0 = 2350                                       # x0 center point of sphere
    # (np.max(mesh.gridCC[:, 2]) + np.min(mesh.gridCC[:, 2])) / 2.
    r0 = 500                                           # radius of sphere
    print(x0, y0, z0)
    csph = (np.sqrt((mesh.gridCC[:, 0] - x0)**2. +
                    (mesh.gridCC[:, 1] - y0)**2. +
                    (mesh.gridCC[:, 2] - z0)**2.)) < r0  # indicies of sphere
# sphere done =================================================================

# ============================================================================
# Create model
    mx = np.ones(mesh.nC) * 0.020                         # chargeability
    sigma = np.ones(mesh.nC) * 1. / 15000.

# create dipping structure parameters
    theta = 45. * np.pi / 180.                            # dipping angle
    x0_d = 374700.
    x1_d = 375000.
    y0_d = 6275850.
    y0_1d = 500. * np.sin(theta) + y0_d
    y1_d = 6275900.
    y1_1d = 500. * np.sin(theta) + y1_d
    z0_d = 1860.
    z1_d = z0_d - (500. * np.cos(theta))
    m_ = (z0_d - z1_d) / (y0_1d - y0_d)                   # slope of dip

    # loop through mesh and assign dipping structure conductivity
    for idx in range(mesh.nC):
        if z1_d <= mesh.gridCC[idx, 2] <= z0_d:
            if (x0_d <= mesh.gridCC[idx, 0] <= x1_d):
                yslope1 = y0_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d)
                yslope2 = y1_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d)
                if yslope1 <= mesh.gridCC[idx, 1] <= yslope2:
                    mx[idx] = 0.03
                    sigma[idx] = 1. / 300.

    # mx[csph] = ((0.025) *
    #             np.ones_like(mx[csph]))             # set sphere values
    mx[~actinds] = 1. / 1e8                             # flag air values
    # sigma[csph] = ((5000.) *
    #                np.ones_like(sigma[csph]))             # set sphere values
    sigma[~actinds] = 1. / 1e8                              # flag air values
    rho = 1. / sigma
    stop = clock()
    print(stop)
    # plot results
    # Show the true conductivity model
    if plotIt:
        ncy = mesh.nCy
        ncz = mesh.nCz
        ncx = mesh.nCx
        mtrue = mx
        print(mtrue.min(), mtrue.max())
        clim = [0, 0.04]
        fig, ax = plt.subplots(2, 2, figsize=(12, 6))
        ax = Utils.mkvc(ax)
        dat = mesh.plotSlice(((mx)), ax=ax[0], normal='Z', clim=clim,
                             ind=int(ncz / 2), pcolorOpts={"cmap": "jet"})
        ax[0].plot(rx[:, 0], rx[:, 1], 'or')
        ax[0].plot(tx[:, 0], tx[:, 1], 'dk')
        mesh.plotSlice(((mx)), ax=ax[1], normal='Y', clim=clim,
                       ind=int(ncy / 2 + 2), pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mx)), ax=ax[2], normal='X', clim=clim,
                       ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mx)), ax=ax[3], normal='X', clim=clim,
                       ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"})
        cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7])
        cb = plt.colorbar(dat[0], ax=cbar_ax)
        fig.subplots_adjust(right=0.85)
        cb.set_label('V/V')
        cbar_ax.axis('off')
        plt.show()

        mtrue = 1. / sigma
        print(mtrue.min(), mtrue.max())
        clim = [0, 20000]
        fig, ax = plt.subplots(2, 2, figsize=(12, 6))
        ax = Utils.mkvc(ax)
        dat = mesh.plotSlice(((mtrue)), ax=ax[0], normal='Z', clim=clim,
                             ind=int(ncz / 2 - 4), pcolorOpts={"cmap": "jet"})
        ax[0].plot(rx[:, 0], rx[:, 1], 'or')
        ax[0].plot(tx[:, 0], tx[:, 1], 'dk')
        mesh.plotSlice(((mtrue)), ax=ax[1], normal='Y', clim=clim,
                       ind=int(ncy / 2), pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mtrue)), ax=ax[2], normal='X', clim=clim,
                       ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"})
        mesh.plotSlice(((mtrue)), ax=ax[3], normal='X', clim=clim,
                       ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"})
        cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7])
        cb = plt.colorbar(dat[0], ax=cbar_ax)
        fig.subplots_adjust(right=0.85)
        cb.set_label('rho')
        cbar_ax.axis('off')
        plt.show()

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

    # Generate mtrue_dc for resistivity
    mtrue_dc = np.log(rho[actinds])

    # Generate 3D DC problem
    # "CC" means potential is defined at center
    prb = DC.Problem3D_CC(
        mesh, rhoMap=mapping, storeJ=False,
        Solver=Solver
    )
    # Pair problem with survey
    try:
        prb.pair(survey_dc)
    except:
        survey_dc.unpair()
        prb.pair(survey_dc)

    # Make synthetic DC data with 5% Gaussian noise
    dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True)
    IO.data_dc = dtrue_dc
    # Generate mtrue_ip for chargability
    mtrue_ip = mx[actinds]
    # Generate 3D DC problem
    # "CC" means potential is defined at center
    prb_ip = IP.Problem3D_CC(
        mesh, etaMap=actmap, storeJ=False, rho=rho,
        Solver=Solver
    )
    survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="3D")
    prb_ip.pair(survey_ip)
    dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05)
    IO.data_ip = dtrue_ip

    # Show apparent resisitivty histogram
    # if plotIt:
    #     fig = plt.figure(figsize=(10, 4))
    #     ax1 = plt.subplot(121)
    #     out = hist(np.log10(abs(IO.voltages)), bins=20)
    #     ax1.set_xlabel("log10 DC voltage (V)")
    #     ax2 = plt.subplot(122)
    #     out = hist(IO.apparent_resistivity, bins=20)
    #     ax2.set_xlabel("Apparent Resistivity ($\Omega$m)")
    #     plt.tight_layout()
    #     plt.show()

    # Set initial model based upon histogram
    m0_dc = np.ones(actmap.nP) * np.log(10000.)
    # Set uncertainty
    # floor
    eps_dc = 10**(-3.2)
    # percentage
    std_dc = 0.05

    mopt_dc, pred_dc = DC.run_inversion(
        m0_dc, survey_dc, actinds, mesh, std_dc, eps_dc,
        use_sensitivity_weight=False)

    # Convert obtained inversion model to resistivity
    # rho = M(m), where M(.) is a mapping
    rho_est = mapping * mopt_dc
    # rho_est[~actinds] = np.nan
    rho_true = rho.copy()
    rho_true[~actinds] = np.nan

    # write data to file
    out_file = open(fileName1, "w")
    for i in range(rho_est.size):
        out_file.write("%0.5e\n" % rho_est[i])

    # Set initial model based upon histogram
    m0_ip = np.ones(actmap.nP) * 1e-10
    # Set uncertainty
    # floor
    eps_ip = 10**(-4)
    # percentage
    std_ip = 0.05
    # Clean sensitivity function formed with true resistivity
    prb_ip._Jmatrix = None
    # Input obtained resistivity to form sensitivity
    prb_ip.rho = mapping * mopt_dc
    mopt_ip, _ = IP.run_inversion(
        m0_ip, survey_ip, actinds, mesh, std_ip, eps_ip,
        upper=np.Inf, lower=0.,
        use_sensitivity_weight=False)

    # Convert obtained inversion model to chargeability
    # charg = M(m), where M(.) is a mapping for cells below topography
    charg_est = actmap * mopt_ip
    # charg_est[~actinds] = np.nan
    charg_true = charg.copy()
    charg_true[~actinds] = np.nan

    # write IP data to file
    out_file = open(fileName1_, "w")
    for i in range(charg_est.size):
        out_file.write("%0.5e\n" % charg_est[i])
Esempio n. 40
0
    def setUp(self):

        ndv = -100
        # Create a mesh
        dx = 5.

        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)]

        mesh = 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]

        # Go from topo to actv cells
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]
        actv = Utils.surface2ind_topo(mesh, topo, 'N')
        actv = np.asarray([inds for inds, elem in enumerate(actv, 1)
                          if elem], dtype=int) - 1

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

        # Create and array of observation points
        xr = np.linspace(-20., 20., 20)
        yr = np.linspace(-20., 20., 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.

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

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

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

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

        # Create the forward model operator
        prob = PF.Gravity.GravityIntegral(
            mesh,
            rhoMap=idenMap,
            actInd=actv
        )

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

        # Compute linear forward operator and compute some data
        d = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        data = d + np.random.randn(len(d))*0.001
        wd = np.ones(len(data))*.001

        survey.dobs = data
        survey.std = wd

        # PF.Gravity.plot_obs_2D(survey.srcField.rxList[0].locs, d=data)

        # Create sensitivity weights from our linear forward operator
        wr = PF.Magnetics.get_dist_wgt(mesh, locXYZ, actv, 2., 2.)
        wr = wr**2.

        # Create a regularization
        reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
        reg.cell_weights = wr
        reg.norms = [0, 1, 1, 1]
        reg.eps_p, reg.eps_q = 5e-2, 1e-2

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

        # Add directives to the inversion
        opt = Optimization.ProjectedGNCG(maxIter=100, lower=-1., upper=1.,
                                         maxIterLS=20, maxIterCG=10,
                                         tolCG=1e-3)
        invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+8)

        # Here is where the norms are applied
        IRLS = Directives.Update_IRLS(f_min_change=1e-3,
                                      minGNiter=3)
        update_Jacobi = Directives.Update_lin_PreCond(mapping=idenMap)

        self.inv = Inversion.BaseInversion(invProb,
                                           directiveList=[IRLS,
                                                          update_Jacobi])
Esempio n. 41
0
def run(plotIt=True):

    # Create a mesh
    dx = 5.

    hxind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)]
    hyind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)]
    hzind = [(dx, 5, -1.3), (dx, 7), (3.5, 1), (2, 5)]

    mesh = 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 actv cells
    actv = Utils.surface2ind_topo(mesh, topo, 'N')
    actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem],
                      dtype=int) - 1

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

    # Create and array of observation points
    xr = np.linspace(-30., 30., 20)
    yr = np.linspace(-30., 30., 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] + 0.1

    # Create a MAGsurvey
    rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
    rxLoc = PF.BaseGrav.RxObs(rxLoc)
    srcField = PF.BaseGrav.SrcField([rxLoc])
    survey = PF.BaseGrav.LinearSurvey(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-5):(midx-1), (midy-2):(midy+2), -10:-6] = 0.5
    model[(midx+1):(midx+5), (midy-2):(midy+2), -10:-6] = -0.5
    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
    prob = PF.Gravity.GravityIntegral(mesh, rhoMap=idenMap, actInd=actv)

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

    # Compute linear forward operator and compute some data
    d = prob.fields(model)

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

    survey.dobs = data
    survey.std = wd
    survey.mtrue = model

    # Create sensitivity weights from our linear forward operator
    rxLoc = survey.srcField.rxList[0].locs
    wr = np.sum(prob.G**2., axis=0)**0.5
    wr = (wr/np.max(wr))

    # Create a regularization
    reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
    reg.cell_weights = wr
    reg.norms = [0, 1, 1, 1]

    # Data misfit function
    dmis = DataMisfit.l2_DataMisfit(survey)
    dmis.W = Utils.sdiag(1/wd)

    # Add directives to the inversion
    opt = Optimization.ProjectedGNCG(maxIter=100, lower=-1., upper=1.,
                                     maxIterLS=20, maxIterCG=10,
                                     tolCG=1e-3)
    invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
    betaest = Directives.BetaEstimate_ByEig()

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

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

    if plotIt:
        # Here is the recovered susceptibility model
        ypanel = midx
        zpanel = -7
        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

        vmin, vmax = mrec.min(), mrec.max()

        # Plot the data
        PF.Gravity.plot_obs_2D(rxLoc, d=data)

        plt.figure()

        # Plot L2 model
        ax = plt.subplot(321)
        mesh.plotSlice(m_l2, ax=ax, normal='Z', ind=zpanel,
                       grid=True, clim=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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=(vmin, vmax))
        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')
Esempio n. 42
0
    def setUp(self):
        # We will assume a vertical inducing field
        H0 = (50000., 90., 0.)

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

        # Block with an effective susceptibility
        chi_e = 0.05

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                zOffset += dx

        mesh.finalize()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.mesh = mesh
Esempio n. 43
0
                    rxLoc[:, 1] > ylim[0], rxLoc[:, 1] < ylim[1]], axis=0)

    if np.sum(ind_t) < 20:
        continue

    rxLoc_t = PF.BaseMag.RxObs(rxLoc[ind_t, :])
    srcField = PF.BaseMag.SrcField([rxLoc_t], param=survey.srcField.param)
    survey_t = PF.BaseMag.LinearSurvey(srcField)
    survey_t.dobs = survey.dobs[ind_t]
    survey_t.std = survey.std[ind_t]

    # Extract model from global to local mesh
    if driver.topofile is not None:
        topo = np.genfromtxt(work_dir + driver.topofile,
                             skip_header=1)
        actv = Utils.surface2ind_topo(mesh_t, topo, 'N')
        actv = np.asarray(np.where(mkvc(actv))[0], dtype=int)
    else:
        actv = np.ones(mesh_t.nC, dtype='bool')

    nC = len(actv)
    # print("Tile "+str(tt))
    print(nC, np.sum(ind_t))
    # Create active map to go from reduce space to full
    actvMap = Maps.InjectActiveCells(mesh_t, actv, -100)

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

    mstart = np.ones(nC)*1e-4
Esempio n. 44
0
    def createLocalProb(rxLoc, wrGlobal, lims):

        # Grab the data for current tile
        ind_t = np.all([
            rxLoc[:, 0] >= lims[0], rxLoc[:, 0] <= lims[1],
            rxLoc[:, 1] >= lims[2], rxLoc[:, 1] <= lims[3], surveyMask
        ],
                       axis=0)

        # Remember selected data in case of tile overlap
        surveyMask[ind_t] = False

        # Create new survey
        rxLoc_t = PF.BaseGrav.RxObs(rxLoc[ind_t, :])
        srcField = PF.BaseGrav.SrcField([rxLoc_t])
        survey_t = PF.BaseGrav.LinearSurvey(srcField)
        survey_t.dobs = survey.dobs[ind_t]
        survey_t.std = survey.std[ind_t]
        survey_t.ind = ind_t

        # mesh_t = meshTree.copy()
        mesh_t = Utils.modelutils.meshBuilder(rxLoc[ind_t, :],
                                              h,
                                              padDist,
                                              meshGlobal=meshInput,
                                              meshType='TREE',
                                              gridLoc='CC')

        mesh_t = Utils.modelutils.refineTree(mesh_t,
                                             topo,
                                             dtype='surface',
                                             nCpad=[0, 3, 2],
                                             finalize=False)

        mesh_t = Utils.modelutils.refineTree(mesh_t,
                                             rxLoc[ind_t, :],
                                             dtype='surface',
                                             nCpad=[10, 5, 5],
                                             finalize=False)

        center = np.mean(rxLoc[ind_t, :], axis=0)
        tileCenter = np.r_[np.mean(lims[0:2]), np.mean(lims[2:]), center[2]]

        ind = closestPoints(mesh, tileCenter, gridLoc='CC')

        shift = np.squeeze(mesh.gridCC[ind, :]) - center

        mesh_t.x0 += shift
        mesh_t.finalize()

        print(mesh_t.nC)
        actv_t = Utils.surface2ind_topo(mesh_t, topo)

        # Create reduced identity map
        tileMap = Maps.Tile((mesh, actv), (mesh_t, actv_t))
        tileMap.nCell = 40
        tileMap.nBlock = 1

        # Create the forward model operator
        prob = PF.Gravity.GravityIntegral(mesh_t,
                                          rhoMap=tileMap,
                                          actInd=actv_t,
                                          memory_saving_mode=True,
                                          parallelized=True)
        survey_t.pair(prob)

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

        wrGlobal += prob.getJtJdiag(np.ones(tileMap.P.shape[1]))

        # Create combo misfit function
        return dmis, wrGlobal
Esempio n. 45
0
ind = Utils.ModelBuilder.getIndicesSphere(loc, radi, mesh.gridCC)
model[ind] = sig[1]

# Create quick topo
xtopo, ytopo = np.meshgrid(mesh.vectorNx, mesh.vectorNy)
ztopo = np.zeros_like(xtopo)

topo = np.c_[mkvc(xtopo), mkvc(ytopo), mkvc(ztopo)]

# Write out topo file
fid = open('Topo.topo', 'w')
fid.write(str(topo.shape[0]) + '\n')
np.savetxt(fid, topo, fmt='%f', delimiter=' ', newline='\n')
fid.close()

ind = Utils.surface2ind_topo(mesh, topo, gridLoc='N')

# Change aircells
model[ind == 0] = air

# Write out model
Mesh.TensorMesh.writeUBC(mesh, 'Mesh.msh')
Mesh.TensorMesh.writeModelUBC(mesh, mfile, model)

# Create survey locs centered about origin and write to file
locx, locy = np.meshgrid(np.linspace(-xlim, xlim, nstn),
                         np.linspace(-xlim, xlim, nstn))
locz = np.ones_like(locx) * rx_height

rxLoc = np.c_[mkvc(locx), mkvc(locy), mkvc(locz)]
Esempio n. 46
0
    def setUp(self):

        np.random.seed(0)

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

        # Create a mesh
        dx = 5.0

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

        mesh = 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]

        # Go from topo to actv cells
        topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)]
        actv = Utils.surface2ind_topo(mesh, topo, "N")
        actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem], dtype=int) - 1

        # Create active map to go from reduce space to full
        actvMap = Maps.InjectActiveCells(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) + mesh.vectorNz[-1] + 5.0

        # Create a MAGsurvey
        rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)]
        rxLoc = PF.BaseMag.RxObs(rxLoc)
        srcField = PF.BaseMag.SrcField([rxLoc], param=H0)
        survey = PF.BaseMag.LinearSurvey(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)
        self.model = model[actv]

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

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

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

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

        # Compute linear forward operator and compute some data
        d = prob.fields(self.model)

        # Add noise and uncertainties (1nT)
        data = d + np.random.randn(len(d))
        wd = np.ones(len(data)) * 1.0

        survey.dobs = data
        survey.std = wd

        # Create sensitivity weights from our linear forward operator
        wr = np.sum(prob.G ** 2.0, axis=0) ** 0.5
        wr = wr / np.max(wr)

        # Create a regularization
        reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap)
        reg.cell_weights = wr

        # Data misfit function
        dmis = DataMisfit.l2_DataMisfit(survey)
        dmis.Wd = 1 / wd

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

        invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
        betaest = Directives.BetaEstimate_ByEig()

        # Here is where the norms are applied
        IRLS = Directives.Update_IRLS(norms=([0, 1, 1, 1]), eps=(1e-3, 1e-3), f_min_change=1e-3, minGNiter=3)
        update_Jacobi = Directives.Update_lin_PreCond()
        self.inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi])
    def setUp(self):
        # We will assume a vertical inducing field
        H0 = (50000., 90., 0.)

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

        # Block with an effective susceptibility
        chi_e = 0.05

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                zOffset += dx

        mesh.finalize()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.mesh = mesh
Esempio n. 48
0
    z = F(mkvc(CCx), mkvc(CCy))

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

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

        zOffset += dx

mesh.finalize()

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

###########################################################################
# A simple function to plot vectors in TreeMesh
#
# Should eventually end up on discretize
#


def plotVectorSectionsOctree(mesh,
                             m,
                             normal='X',
                             ind=0,
                             vmin=None,
                             vmax=None,
Esempio n. 49
0
    def set_mesh(self,
                 topo=None,
                 dx=None,
                 dy=None,
                 dz=None,
                 n_spacing=None,
                 corezlength=None,
                 npad_x=7,
                 npad_y=7,
                 npad_z=7,
                 pad_rate_x=1.3,
                 pad_rate_y=1.3,
                 pad_rate_z=1.3,
                 ncell_per_dipole=4,
                 mesh_type='TensorMesh',
                 dimension=2,
                 method='linear'):
        """
        Set up a mesh for a given DC survey
        """
        if mesh_type == 'TreeMesh':
            raise NotImplementedError()

        # 2D or 3D mesh
        if dimension in [2, 3]:
            if dimension == 2:
                z_ind = 1
            else:
                z_ind = 2
            a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min()
            lineLength = abs(self.electrode_locations[:, 0].max() -
                             self.electrode_locations[:, 0].min())
            dx_ideal = a / ncell_per_dipole
            if dx is None:
                dx = dx_ideal
                warnings.warn(
                    "dx is set to {} m (samllest electrode spacing ({}) / {})".
                    format(dx, a, ncell_per_dipole))
            if dz is None:
                dz = dx * 0.5
                warnings.warn("dz ({} m) is set to dx ({} m) / {}".format(
                    dz, dx, 2))
            x0 = self.electrode_locations[:, 0].min()
            if topo is None:
                locs = self.electrode_locations
            else:
                locs = np.vstack((topo, self.electrode_locations))

            if dx > dx_ideal:
                # warnings.warn(
                #     "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a)
                # )
                pass
            self.dx = dx
            self.dz = dz
            self.npad_x = npad_x
            self.npad_z = npad_z
            self.pad_rate_x = pad_rate_x
            self.pad_rate_z = pad_rate_z
            self.ncell_per_dipole = ncell_per_dipole
            zmax = locs[:, z_ind].max()
            zmin = locs[:, z_ind].min()

            # 3 cells each for buffer
            corexlength = lineLength + dx * 6
            if corezlength is None:
                corezlength = self.grids[:, z_ind].max()

            ncx = np.round(corexlength / dx)
            ncz = np.round(corezlength / dz)
            hx = [(dx, npad_x, -pad_rate_x), (dx, ncx),
                  (dx, npad_x, pad_rate_x)]
            hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)]
            x0_mesh = -(
                (dx * pad_rate_x**(np.arange(npad_x) + 1)).sum() + dx * 3 - x0)
            z0_mesh = -((dz * pad_rate_z**
                         (np.arange(npad_z) + 1)).sum() + dz * ncz) + zmax

            # For 2D mesh
            if dimension == 2:
                h = [hx, hz]
                x0_for_mesh = [x0_mesh, z0_mesh]
                self.xyzlim = np.vstack(
                    (np.r_[x0, x0 + lineLength], np.r_[zmax - corezlength,
                                                       zmax]))

            # For 3D mesh
            else:
                if dy is None:
                    raise Exception("You must input dy (m)")

                self.dy = dy
                self.npad_y = npad_y
                self.pad_rate_y = pad_rate_y

                ylocs = np.unique(self.electrode_locations[:, 1])
                ymin, ymax = ylocs.min(), ylocs.max()
                # 3 cells each for buffer in y-direction
                coreylength = ymax - ymin + dy * 6
                ncy = np.round(coreylength / dy)
                hy = [(dy, npad_y, -pad_rate_y), (dy, ncy),
                      (dy, npad_y, pad_rate_y)]
                y0 = ylocs.min() - dy / 2.
                y0_mesh = -((dy * pad_rate_y**(np.arange(npad_y) + 1)).sum() +
                            dy * 3 - y0)

                h = [hx, hy, hz]
                x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh]
                self.xyzlim = np.vstack(
                    (np.r_[x0, x0 + lineLength], np.r_[ymin, ymax],
                     np.r_[zmax - corezlength, zmax]))
            mesh = Mesh.TensorMesh(h, x0=x0_for_mesh)
            actind = Utils.surface2ind_topo(mesh, locs, method=method)
        else:
            raise NotImplementedError()

        return mesh, actind