Example #1
0
    def face_y_areas(self):
        """Returns the areas of the y-faces

        Calling this property will compute and return the areas of faces
        whose normal vector is along the y-axis. Note that only 2D and 3D
        tensor meshes have z-faces.

        Returns
        -------
        (n_faces_y) numpy.ndarray
            The quantity returned depends on the dimensions of the mesh:

            - *1D:* N/A since 1D meshes do not have y-faces
            - *2D:* Areas of y-faces (equivalent to the lengths of x-edges)
            - *3D:* Areas of y-faces
        """
        if getattr(self, "_face_y_areas", None) is None:
            # Ensure that we are working with column vectors
            vh = self.h
            # The number of cell centers in each direction
            n = self.vnC
            # Compute areas of cell faces
            if self.dim == 1:
                raise Exception("1D meshes do not have y-Faces")
            elif self.dim == 2:
                areaFy = np.outer(vh[0], np.ones(n[1] + 1))
            elif self.dim == 3:
                areaFy = np.outer(vh[0], mkvc(np.outer(np.ones(n[1] + 1), vh[2])))
            self._face_y_areas = mkvc(areaFy)
        return self._face_y_areas
Example #2
0
    def face_z_areas(self):
        """Returns the areas of the z-faces

        Calling this property will compute and return the areas of faces
        whose normal vector is along the z-axis. Note that only 3D tensor
        meshes will have z-faces.

        Returns
        -------
        (n_faces_z) numpy.ndarray
            The quantity returned depends on the dimensions of the mesh:

            - *1D:* N/A since 1D meshes do not have z-faces
            - *2D:* N/A since 2D meshes do not have z-faces
            - *3D:* Areas of z-faces
        """
        if getattr(self, "_face_z_areas", None) is None:
            # Ensure that we are working with column vectors
            vh = self.h
            # The number of cell centers in each direction
            n = self.vnC
            # Compute areas of cell faces
            if self.dim == 1 or self.dim == 2:
                raise Exception("{}D meshes do not have z-Faces".format(self.dim))
            elif self.dim == 3:
                areaFz = np.outer(vh[0], mkvc(np.outer(vh[1], np.ones(n[2] + 1))))
            self._face_z_areas = mkvc(areaFz)
        return self._face_z_areas
    def faces_y(self):
        """
        Face staggered grid in the y direction.
        """

        if getattr(self, "_faces_y", None) is None:
            N = self.reshape(self.gridN, "N", "N", "M")
            if self.dim == 2:
                XY = [mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
                self._faces_y = np.c_[XY[0], XY[1]]
            elif self.dim == 3:
                XYZ = [
                    mkvc(
                        0.25
                        * (
                            n[:-1, :, :-1]
                            + n[:-1, :, 1:]
                            + n[1:, :, :-1]
                            + n[1:, :, 1:]
                        )
                    )
                    for n in N
                ]
                self._faces_y = np.c_[XYZ[0], XYZ[1], XYZ[2]]
        return self._faces_y
Example #4
0
    def edge_x_lengths(self):
        """Returns the x-edge lengths

        Calling this property will compute and return the lengths of edges
        parallel to the x-axis.

        Returns
        -------
        (n_edges_x) numpy.ndarray
            X-edge lengths
        """
        if getattr(self, "_edge_x_lengths", None) is None:
            # Ensure that we are working with column vectors
            vh = self.h
            # The number of cell centers in each direction
            n = self.vnC
            # Compute edge lengths
            if self.dim == 1:
                edgeEx = vh[0]
            elif self.dim == 2:
                edgeEx = np.outer(vh[0], np.ones(n[1] + 1))
            elif self.dim == 3:
                edgeEx = np.outer(
                    vh[0], mkvc(np.outer(np.ones(n[1] + 1), np.ones(n[2] + 1)))
                )
            self._edge_x_lengths = mkvc(edgeEx)
        return self._edge_x_lengths
Example #5
0
    def cell_volumes(self):
        """Return cell volumes

        Calling this property will compute and return the volumes of the tensor
        mesh cells.

        Returns
        -------
        (n_cells) numpy.ndarray
            The quantity returned depends on the dimensions of the mesh:

            - *1D:* Returns the cell widths
            - *2D:* Returns the cell areas
            - *3D:* Returns the cell volumes

        """
        if getattr(self, "_cell_volumes", None) is None:
            vh = self.h
            # Compute cell volumes
            if self.dim == 1:
                self._cell_volumes = mkvc(vh[0])
            elif self.dim == 2:
                # Cell sizes in each direction
                self._cell_volumes = mkvc(np.outer(vh[0], vh[1]))
            elif self.dim == 3:
                # Cell sizes in each direction
                self._cell_volumes = mkvc(np.outer(mkvc(np.outer(vh[0], vh[1])), vh[2]))
        return self._cell_volumes
Example #6
0
    def edge_z_lengths(self):
        """Returns the z-edge lengths

        Calling this property will compute and return the lengths of edges
        parallel to the z-axis.

        Returns
        -------
        (n_edges_z) numpy.ndarray
            The quantity returned depends on the dimensions of the mesh:

            - *1D:* N/A since 1D meshes do not have z-edges
            - *2D:* N/A since 2D meshes do not have z-edges
            - *3D:* Returns z-edge lengths
        """
        if getattr(self, "_edge_z_lengths", None) is None:
            # Ensure that we are working with column vectors
            vh = self.h
            # The number of cell centers in each direction
            n = self.vnC
            # Compute edge lengths
            if self.dim == 1 or self.dim == 2:
                raise Exception("{}D meshes do not have y-edges".format(self.dim))
            elif self.dim == 3:
                edgeEz = np.outer(
                    np.ones(n[0] + 1), mkvc(np.outer(np.ones(n[1] + 1), vh[2]))
                )
            self._edge_z_lengths = mkvc(edgeEz)
        return self._edge_z_lengths
Example #7
0
 def edge_lengths(self):
     if getattr(self, "_edge_lengths", None) is None:
         if self.dim == 2:
             xy = self.gridN
             A, D = index_cube("AD", self.vnN, self.vnEx)
             edge1 = xy[D, :] - xy[A, :]
             A, B = index_cube("AB", self.vnN, self.vnEy)
             edge2 = xy[B, :] - xy[A, :]
             self._edge_lengths = np.r_[
                 mkvc(_length2D(edge1)), mkvc(_length2D(edge2))
             ]
             self._edge_tangents = (
                 np.r_[edge1, edge2] / np.c_[self._edge_lengths, self._edge_lengths]
             )
         elif self.dim == 3:
             xyz = self.gridN
             A, D = index_cube("AD", self.vnN, self.vnEx)
             edge1 = xyz[D, :] - xyz[A, :]
             A, B = index_cube("AB", self.vnN, self.vnEy)
             edge2 = xyz[B, :] - xyz[A, :]
             A, E = index_cube("AE", self.vnN, self.vnEz)
             edge3 = xyz[E, :] - xyz[A, :]
             self._edge_lengths = np.r_[
                 mkvc(_length3D(edge1)),
                 mkvc(_length3D(edge2)),
                 mkvc(_length3D(edge3)),
             ]
             self._edge_tangents = (
                 np.r_[edge1, edge2, edge3]
                 / np.c_[self._edge_lengths, self._edge_lengths, self._edge_lengths]
             )
     return self._edge_lengths
Example #8
0
    def face_x_areas(self):
        """Returns the areas of the x-faces

        Calling this property will compute and return the areas of faces
        whose normal vector is along the x-axis.

        Returns
        -------
        (n_faces_x) numpy.ndarray
            The quantity returned depends on the dimensions of the mesh:

            - *1D:* Numpy array of ones whose length is equal to the number of nodes
            - *2D:* Areas of x-faces (equivalent to the lengths of y-edges)
            - *3D:* Areas of x-faces
        """
        if getattr(self, "_face_x_areas", None) is None:
            # Ensure that we are working with column vectors
            vh = self.h
            # The number of cell centers in each direction
            n = self.vnC
            # Compute areas of cell faces
            if self.dim == 1:
                areaFx = np.ones(n[0] + 1)
            elif self.dim == 2:
                areaFx = np.outer(np.ones(n[0] + 1), vh[1])
            elif self.dim == 3:
                areaFx = np.outer(np.ones(n[0] + 1), mkvc(np.outer(vh[1], vh[2])))
            self._face_x_areas = mkvc(areaFx)
        return self._face_x_areas
Example #9
0
    def edges_y(self):
        """Gridded y-edge locations (staggered grid)

        This property returns a numpy array of shape (n_edges_y, dim)
        containing gridded locations for all y-edges in the
        mesh (staggered grid). For curvilinear meshes whose structure
        is minimally staggered, the y-edges are edges oriented
        primarily along the y-direction. For highly irregular
        meshes however, this is not the case; see the examples below.

        Returns
        -------
        (n_edges_y, dim) numpy.ndarray of float
            Gridded y-edge locations (staggered grid)

        Examples
        --------
        Here, we provide an example of a minimally staggered curvilinear mesh.
        In this case, the y-edges are primarily oriented along the y-direction.

        >>> from discretize import CurvilinearMesh
        >>> from discretize.utils import example_curvilinear_grid, mkvc
        >>> from matplotlib import pyplot as plt

        >>> x, y = example_curvilinear_grid([10, 10], "rotate")
        >>> mesh1 = CurvilinearMesh([x, y])
        >>> y_edges = mesh1.edges_y

        >>> fig1 = plt.figure(figsize=(5, 5))
        >>> ax1 = fig1.add_subplot(111)
        >>> mesh1.plot_grid(ax=ax1)
        >>> ax1.scatter(y_edges[:, 0], y_edges[:, 1], 30, 'r')
        >>> ax1.legend(['Mesh', 'Y-edges'], fontsize=16)
        >>> plt.plot()

        Here, we provide an example of a highly irregular curvilinear mesh.
        In this case, the y-edges are not aligned primarily along
        a particular direction.

        >>> x, y = example_curvilinear_grid([10, 10], "sphere")
        >>> mesh2 = CurvilinearMesh([x, y])
        >>> y_edges = mesh2.edges_y

        >>> fig2 = plt.figure(figsize=(5, 5))
        >>> ax2 = fig2.add_subplot(111)
        >>> mesh2.plot_grid(ax=ax2)
        >>> ax2.scatter(y_edges[:, 0], y_edges[:, 1], 30, 'r')
        >>> ax2.legend(['Mesh', 'X-edges'], fontsize=16)
        >>> plt.plot()
        """
        if getattr(self, "_edges_y", None) is None:
            N = self.reshape(self.gridN, "N", "N", "M")
            if self.dim == 2:
                XY = [mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
                self._edges_y = np.c_[XY[0], XY[1]]
            elif self.dim == 3:
                XYZ = [mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N]
                self._edges_y = np.c_[XYZ[0], XYZ[1], XYZ[2]]
        return self._edges_y
Example #10
0
    def face_areas(self):
        """Returns the areas of all faces in the mesh

        Calling this property will compute and return the areas of all
        faces as a 1D numpy array. The returned quantity is ordered x-face
        areas, then y-face areas, then z-face areas.

        Returns
        -------
        (n_faces) numpy.ndarray
            The length of the quantity returned depends on the dimensions of the mesh:

            - *1D:* returns the x-face areas
            - *2D:* returns the x-face and y-face areas in order; i.e. y-edge
              and x-edge lengths, respectively
            - *3D:* returns the x, y and z-face areas in order
        """
        if (
            getattr(self, "_face_areas", None) is None
            or getattr(self, "_normals", None) is None
        ):
            # Compute areas of cell faces
            if self.dim == 2:
                xy = self.gridN
                A, B = index_cube("AB", self.vnN, self.vnFx)
                edge1 = xy[B, :] - xy[A, :]
                normal1 = np.c_[edge1[:, 1], -edge1[:, 0]]
                area1 = _length2D(edge1)
                A, D = index_cube("AD", self.vnN, self.vnFy)
                # Note that we are doing A-D to make sure the normal points the
                # right way.
                # Think about it. Look at the picture. Normal points towards C
                # iff you do this.
                edge2 = xy[A, :] - xy[D, :]
                normal2 = np.c_[edge2[:, 1], -edge2[:, 0]]
                area2 = _length2D(edge2)
                self._face_areas = np.r_[mkvc(area1), mkvc(area2)]
                self._normals = [_normalize2D(normal1), _normalize2D(normal2)]

            elif self.dim == 3:

                A, E, F, B = index_cube("AEFB", self.vnN, self.vnFx)
                normal1, area1 = face_info(
                    self.gridN, A, E, F, B, average=False, normalizeNormals=False
                )

                A, D, H, E = index_cube("ADHE", self.vnN, self.vnFy)
                normal2, area2 = face_info(
                    self.gridN, A, D, H, E, average=False, normalizeNormals=False
                )

                A, B, C, D = index_cube("ABCD", self.vnN, self.vnFz)
                normal3, area3 = face_info(
                    self.gridN, A, B, C, D, average=False, normalizeNormals=False
                )

                self._face_areas = np.r_[mkvc(area1), mkvc(area2), mkvc(area3)]
                self._normals = [normal1, normal2, normal3]
        return self._face_areas
Example #11
0
    def getError(self):
        #Test function
        phi = lambda x: np.cos(0.5 * np.pi * x)
        j_fun = lambda x: -0.5 * np.pi * np.sin(0.5 * np.pi * x)
        q_fun = lambda x: -0.25 * (np.pi**2) * np.cos(0.5 * np.pi * x)

        xc_ana = phi(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        j_ana = j_fun(self.M.gridFx)

        #TODO: Check where our boundary conditions are CCx or Nx
        vecN = self.M.vectorNx
        vecC = self.M.vectorCCx

        phi_bc = phi(vecC[[0, -1]])
        j_bc = j_fun(vecN[[0, -1]])

        P, Pin, Pout = self.M.getBCProjWF([['dirichlet', 'neumann']])

        Mc = self.M.getFaceInnerProduct()
        McI = utils.sdInv(self.M.getFaceInnerProduct())
        V = utils.sdiag(self.M.vol)
        G = -Pin.T * Pin * self.M.faceDiv.T * V
        D = self.M.faceDiv
        j = McI * (G * xc_ana + P * phi_bc)
        q = V * D * Pin.T * Pin * j + V * D * Pout.T * j_bc

        # Rearrange if we know q to solve for x
        A = V * D * Pin.T * Pin * McI * G
        rhs = V * q_ana - V * D * Pin.T * Pin * McI * P * phi_bc - V * D * Pout.T * j_bc
        # A = D*McI*G
        # rhs = q_ana - D*McI*P*phi_bc

        if self.myTest == 'j':
            err = np.linalg.norm((Pin * j - Pin * j_ana), np.inf)
        elif self.myTest == 'q':
            err = np.linalg.norm((q - V * q_ana), np.inf)
        elif self.myTest == 'xc':
            #TODO: fix the null space
            xc, info = sp.linalg.minres(A, rhs, tol=1e-6)
            err = np.linalg.norm((xc - xc_ana), np.inf)
            if info > 0:
                print('Solve does not work well')
                print('ACCURACY', np.linalg.norm(utils.mkvc(A * xc) - rhs))
        elif self.myTest == 'xcJ':
            #TODO: fix the null space
            xc, info = sp.linalg.minres(A, rhs, tol=1e-6)
            j = McI * (G * xc + P * phi_bc)
            err = np.linalg.norm((Pin * j - Pin * j_ana), np.inf)
            if info > 0:
                print('Solve does not work well')
                print('ACCURACY', np.linalg.norm(utils.mkvc(A * xc) - rhs))
        return err
    def test_rotatePointsFromNormals(self):
        np.random.seed(10)
        v0 = np.random.rand(3)
        v0 *= 1.0 / np.linalg.norm(v0)

        np.random.seed(15)
        v1 = np.random.rand(3)
        v1 *= 1.0 / np.linalg.norm(v1)

        v2 = utils.mkvc(
            utils.rotatePointsFromNormals(utils.mkvc(v0, 2).T, v0, v1))

        self.assertTrue(np.linalg.norm(v2 - v1) < tol)
Example #13
0
 def gridEy(self):
     """
     Edge staggered grid in the y direction.
     """
     if getattr(self, '_gridEy', None) is None:
         N = self.r(self.gridN, 'N', 'N', 'M')
         if self.dim == 2:
             XY = [utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
             self._gridEy = np.c_[XY[0], XY[1]]
         elif self.dim == 3:
             XYZ = [utils.mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N]
             self._gridEy = np.c_[XYZ[0], XYZ[1], XYZ[2]]
     return self._gridEy
 def edges_x(self):
     """
     Edge staggered grid in the x direction.
     """
     if getattr(self, "_edges_x", None) is None:
         N = self.reshape(self.gridN, "N", "N", "M")
         if self.dim == 2:
             XY = [mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
             self._edges_x = np.c_[XY[0], XY[1]]
         elif self.dim == 3:
             XYZ = [mkvc(0.5 * (n[:-1, :, :] + n[1:, :, :])) for n in N]
             self._edges_x = np.c_[XYZ[0], XYZ[1], XYZ[2]]
     return self._edges_x
Example #15
0
    def getError(self):
        #Test function
        phi = lambda x: np.cos(np.pi * x)
        j_fun = lambda x: -np.pi * np.sin(np.pi * x)
        q_fun = lambda x: -(np.pi**2) * np.cos(np.pi * x)

        xc_ana = phi(self.M.gridCC)
        q_ana = q_fun(self.M.gridCC)
        j_ana = j_fun(self.M.gridFx)

        #TODO: Check where our boundary conditions are CCx or Nx
        # vec = self.M.vectorNx
        vec = self.M.vectorCCx

        phi_bc = phi(vec[[0, -1]])
        j_bc = j_fun(vec[[0, -1]])

        P, Pin, Pout = self.M.getBCProjWF([['dirichlet', 'dirichlet']])

        Mc = self.M.getFaceInnerProduct()
        McI = utils.sdInv(self.M.getFaceInnerProduct())
        V = utils.sdiag(self.M.vol)
        G = -Pin.T * Pin * self.M.faceDiv.T * V
        D = self.M.faceDiv
        j = McI * (G * xc_ana + P * phi_bc)
        q = V * D * Pin.T * Pin * j + V * D * Pout.T * j_bc

        # Rearrange if we know q to solve for x
        A = V * D * Pin.T * Pin * McI * G
        rhs = V * q_ana - V * D * Pin.T * Pin * McI * P * phi_bc - V * D * Pout.T * j_bc
        # A = D*McI*G
        # rhs = q_ana - D*McI*P*phi_bc

        if self.myTest == 'j':
            err = np.linalg.norm((j - j_ana), np.inf)
        elif self.myTest == 'q':
            err = np.linalg.norm((q - V * q_ana), np.inf)
        elif self.myTest == 'xc':
            #TODO: fix the null space
            solver = SolverCG(A, maxiter=1000)
            xc = solver * (rhs)
            print('ACCURACY', np.linalg.norm(utils.mkvc(A * xc) - rhs))
            err = np.linalg.norm((xc - xc_ana), np.inf)
        elif self.myTest == 'xcJ':
            #TODO: fix the null space
            xc = Solver(A) * (rhs)
            print(np.linalg.norm(utils.mkvc(A * xc) - rhs))
            j = McI * (G * xc + P * phi_bc)
            err = np.linalg.norm((j - j_ana), np.inf)

        return err
Example #16
0
    def test_rotationMatrixFromNormals(self):
        np.random.seed(0)
        v0 = np.random.rand(3)
        v0 *= 1. / np.linalg.norm(v0)

        np.random.seed(5)
        v1 = np.random.rand(3)
        v1 *= 1. / np.linalg.norm(v1)

        Rf = utils.coordutils.rotationMatrixFromNormals(v0, v1)
        Ri = utils.coordutils.rotationMatrixFromNormals(v1, v0)

        self.assertTrue(np.linalg.norm(utils.mkvc(Rf.dot(v0) - v1)) < tol)
        self.assertTrue(np.linalg.norm(utils.mkvc(Ri.dot(v1) - v0)) < tol)
Example #17
0
 def cell_volumes(self):
     if getattr(self, "_cell_volumes", None) is None:
         vh = self.h
         # Compute cell volumes
         if self.dim == 1:
             self._cell_volumes = mkvc(vh[0])
         elif self.dim == 2:
             # Cell sizes in each direction
             self._cell_volumes = mkvc(np.outer(vh[0], vh[1]))
         elif self.dim == 3:
             # Cell sizes in each direction
             self._cell_volumes = mkvc(
                 np.outer(mkvc(np.outer(vh[0], vh[1])), vh[2]))
     return self._cell_volumes
Example #18
0
    def getj3Dthetaslice(self, j3D, theta_ind=0):
        """
        grab theta slice through j
        """
        j3D_x = j3D[:self.mesh3D.nFx].reshape(self.mesh3D.vnFx, order='F')
        j3D_z = j3D[self.mesh3D.vnF[:2].sum():].reshape(self.mesh3D.vnFz,
                                                        order='F')

        j3Dslice = np.vstack([
            utils.mkvc(j3D_x[:, theta_ind, :], 2),
            utils.mkvc(j3D_z[:, theta_ind, :], 2)
        ])

        return j3Dslice
Example #19
0
 def cell_volumes(self):
     """Construct cell volumes of the 3D model as 1d array."""
     if getattr(self, "_cell_volumes", None) is None:
         vh = self.h
         # Compute cell volumes
         if self.dim == 1:
             self._cell_volumes = mkvc(vh[0])
         elif self.dim == 2:
             # Cell sizes in each direction
             self._cell_volumes = mkvc(np.outer(vh[0], vh[1]))
         elif self.dim == 3:
             # Cell sizes in each direction
             self._cell_volumes = mkvc(np.outer(mkvc(np.outer(vh[0], vh[1])), vh[2]))
     return self._cell_volumes
Example #20
0
 def edge_z_lengths(self):
     """z-edge lengths"""
     if getattr(self, "_edge_z_lengths", None) is None:
         # Ensure that we are working with column vectors
         vh = self.h
         # The number of cell centers in each direction
         n = self.vnC
         # Compute edge lengths
         if self.dim == 1 or self.dim == 2:
             raise Exception("{}D meshes do not have y-edges".format(self.dim))
         elif self.dim == 3:
             edgeEz = np.outer(
                 np.ones(n[0] + 1), mkvc(np.outer(np.ones(n[1] + 1), vh[2]))
             )
         self._edge_z_lengths = mkvc(edgeEz)
     return self._edge_z_lengths
Example #21
0
def refine_octree_surface(mesh, f):
    """
    Refine an octree mesh around the given surface
    :param mesh: TreeMesh instance to refine
    :param f: function giving z(x,y) in physical units
    :return: TreeMesh instance
    """
    xx, yy = np.meshgrid(mesh.vectorNx, mesh.vectorNy)
    zz = f(xx, yy)
    idx_valid = ~np.isnan(zz)
    xx, yy, zz = xx[idx_valid], yy[idx_valid], zz[idx_valid]
    surf = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)]
    # Play with different octree_levels=[lx,ly,lz] settings below
    return refine_tree_xyz(
        mesh, surf, octree_levels=[1,1,1], method="surface", finalize=False
    )
Example #22
0
    def write_model_UBC(mesh, file_name, model, directory=""):
        """Write 2D or 3D tensor model to UBC-GIF formatted file.

        Parameters
        ----------
        file_name : str or file name
            full path for the output mesh file or just its name if directory is specified
        model : (n_cells) numpy.ndarray
        directory : str, optional
            output directory
        """
        fname = os.path.join(directory, file_name)
        if mesh.dim == 3:
            # Reshape model to a matrix
            modelMat = mesh.reshape(model, "CC", "CC", "M")
            # Transpose the axes
            modelMatT = modelMat.transpose((2, 0, 1))
            # Flip z to positive down
            modelMatTR = mkvc(modelMatT[::-1, :, :])
            np.savetxt(fname, modelMatTR.ravel())

        elif mesh.dim == 2:
            modelMat = mesh.reshape(model, "CC", "CC", "M").T[::-1]
            f = open(fname, "w")
            f.write("{:d} {:d}\n".format(*mesh.shape_cells))
            f.close()
            f = open(fname, "ab")
            np.savetxt(f, modelMat)
            f.close()

        else:
            raise Exception("mesh must be a Tensor Mesh 2D or 3D")
Example #23
0
    def write_model_UBC(mesh, file_name, model, directory=""):
        """Writes a model associated with a TensorMesh
        to a UBC-GIF format model file.

        Input:
        :param str file_name:  File to write to
        or just its name if directory is specified
        :param str directory: directory where the UBC GIF file lives
        :param numpy.ndarray model: The model
        """
        fname = os.path.join(directory, file_name)
        if mesh.dim == 3:
            # Reshape model to a matrix
            modelMat = mesh.reshape(model, "CC", "CC", "M")
            # Transpose the axes
            modelMatT = modelMat.transpose((2, 0, 1))
            # Flip z to positive down
            modelMatTR = mkvc(modelMatT[::-1, :, :])
            np.savetxt(fname, modelMatTR.ravel())

        elif mesh.dim == 2:
            modelMat = mesh.reshape(model, "CC", "CC", "M").T[::-1]
            f = open(fname, "w")
            f.write("{:d} {:d}\n".format(*mesh.shape_cells))
            f.close()
            f = open(fname, "ab")
            np.savetxt(f, modelMat)
            f.close()

        else:
            raise Exception("mesh must be a Tensor Mesh 2D or 3D")
    def test_zero(self):
        z = Zero()
        assert z == 0
        assert not (z < 0)
        assert z <= 0
        assert not (z > 0)
        assert z >= 0
        assert +z == z
        assert -z == z
        assert z + 1 == 1
        assert z + 3 + z == 3
        assert z - 3 == -3
        assert z - 3 - z == -3
        assert 3 * z == 0
        assert z * 3 == 0
        assert z / 3 == 0

        a = 1
        a += z
        assert a == 1
        a = 1
        a += z
        assert a == 1
        self.assertRaises(ZeroDivisionError, lambda: 3 / z)

        assert mkvc(z) == 0
        assert sdiag(z) * a == 0
        assert z.T == 0
        assert z.transpose() == 0
Example #25
0
    def __init__(self, node_list, **kwargs):

        if "nodes" in kwargs:
            node_list = kwargs.pop("nodes")

        node_list = tuple(np.asarray(item, dtype=np.float64) for item in node_list)
        # check shapes of each node array match
        dim = len(node_list)
        if dim not in [2, 3]:
            raise ValueError(
                f"Only supports 2 and 3 dimensional meshes, saw a node_list of length {dim}"
            )
        for i, nodes in enumerate(node_list):
            if len(nodes.shape) != dim:
                raise ValueError(
                    f"Unexpected shape of item in node list, expect array with {dim} dimensions, got {len(nodes.shape)}"
                )
            if node_list[0].shape != nodes.shape:
                raise ValueError(
                    f"The shape of nodes are not consistent, saw {node_list[0].shape} and {nodes.shape}"
                )
        self._node_list = tuple(node_list)

        # Save nodes to private variable _nodes as vectors
        self._nodes = np.ones((self.node_list[0].size, dim))
        for i, nodes in enumerate(self.node_list):
            self._nodes[:, i] = mkvc(nodes)

        shape_cells = (n - 1 for n in self.node_list[0].shape)

        # absorb the rest of kwargs, and do not pass to super
        super().__init__(shape_cells, origin=self.nodes[0])
Example #26
0
    def faces_z(self):
        """Gridded z-face locations (staggered grid)

        This property returns a numpy array of shape (n_faces_z, dim)
        containing gridded locations for all z-faces in the
        mesh (staggered grid). For curvilinear meshes whose structure
        is minimally staggered, the z-faces are faces whose normal
        vectors are primarily along the z-direction. For highly irregular
        meshes however, this is not the case.

        Returns
        -------
        (n_faces_z, dim) numpy.ndarray of float
            Gridded z-face locations (staggered grid)
        """

        if getattr(self, "_faces_z", None) is None:
            N = self.reshape(self.gridN, "N", "N", "M")
            XYZ = [
                mkvc(
                    0.25
                    * (n[:-1, :-1, :] + n[:-1, 1:, :] + n[1:, :-1, :] + n[1:, 1:, :])
                )
                for n in N
            ]
            self._faces_z = np.c_[XYZ[0], XYZ[1], XYZ[2]]
        return self._faces_z
Example #27
0
 def face_z_areas(self):
     """
     Area of the z-faces
     """
     if getattr(self, "_face_z_areas", None) is None:
         # Ensure that we are working with column vectors
         vh = self.h
         # The number of cell centers in each direction
         n = self.vnC
         # Compute areas of cell faces
         if self.dim == 1 or self.dim == 2:
             raise Exception("{}D meshes do not have z-Faces".format(self.dim))
         elif self.dim == 3:
             areaFz = np.outer(vh[0], mkvc(np.outer(vh[1], np.ones(n[2] + 1))))
         self._face_z_areas = mkvc(areaFz)
     return self._face_z_areas
Example #28
0
def create_box_surface(coordinates, cellwidth, axis='x', degree_rad=0):
    """Creates a list of coordinates of points on the surface of a box.

    Parameters
    ----------
    coordinates : tuple
        ((xmin, xmax),(ymin, ymax),(zmin, zmax)) coordinates of box
    cellwidth : int
        width of smallest cell in the mesh
    axis : string
        'x', 'y' or 'z' to denote the axis of rotation
    degree_rad : float
        the number of degrees to rotate the cube with


    Returns
    -------
    np.ndarray
        a numpy array of the box surface coordinates
    """

    x1 = coordinates[0][0]
    x2 = coordinates[0][1]
    y1 = coordinates[1][0]
    y2 = coordinates[1][1]
    z1 = coordinates[2][0]
    z2 = coordinates[2][1]

    x_num = int(np.ceil((abs(x1 - x2)) / cellwidth))
    y_num = int(np.ceil((abs(y1 - y2)) / cellwidth))
    z_num = int(np.ceil((abs(z1 - z2)) / cellwidth))

    x_coords = np.linspace(x1, x2, x_num)
    y_coords = np.linspace(y1, y2, y_num)
    z_coords = np.linspace(z1, z2, z_num)

    xp, yp, zp = np.meshgrid(x_coords, y_coords, z_coords)
    xyz = np.c_[mkvc(xp), mkvc(yp), mkvc(zp)]
    surface = []
    for row in xyz:
        if row[0] == x1 or row[0] == x2 or row[1] == y1 or row[1] == y2 or row[
                2] == z1 or row[2] == z2:
            surface.append(row)

    rotation = R.from_euler(axis, degree_rad, degrees=True).as_matrix()
    surface = np.asarray([np.dot(rotation, i) for i in surface])
    return np.asarray(surface)
Example #29
0
    def edge_lengths(self):
        """Returns the lengths of all edges in the mesh

        Calling this property will compute and return the lengths of all
        edges in the mesh. The returned quantity is ordered x-edge lengths,
        then y-edge lengths, then z-edge lengths.

        Returns
        -------
        (n_edges) numpy.ndarray
            The length of the quantity returned depends on the dimensions of the mesh:

            - *1D:* returns the x-edge lengths
            - *2D:* returns the x-edge and y-edge lengths in order
            - *3D:* returns the x, y and z-edge lengths in order
        """
        if getattr(self, "_edge_lengths", None) is None:
            if self.dim == 2:
                xy = self.gridN
                A, D = index_cube("AD", self.vnN, self.vnEx)
                edge1 = xy[D, :] - xy[A, :]
                A, B = index_cube("AB", self.vnN, self.vnEy)
                edge2 = xy[B, :] - xy[A, :]
                self._edge_lengths = np.r_[
                    mkvc(_length2D(edge1)), mkvc(_length2D(edge2))
                ]
                self._edge_tangents = (
                    np.r_[edge1, edge2] / np.c_[self._edge_lengths, self._edge_lengths]
                )
            elif self.dim == 3:
                xyz = self.gridN
                A, D = index_cube("AD", self.vnN, self.vnEx)
                edge1 = xyz[D, :] - xyz[A, :]
                A, B = index_cube("AB", self.vnN, self.vnEy)
                edge2 = xyz[B, :] - xyz[A, :]
                A, E = index_cube("AE", self.vnN, self.vnEz)
                edge3 = xyz[E, :] - xyz[A, :]
                self._edge_lengths = np.r_[
                    mkvc(_length3D(edge1)),
                    mkvc(_length3D(edge2)),
                    mkvc(_length3D(edge3)),
                ]
                self._edge_tangents = (
                    np.r_[edge1, edge2, edge3]
                    / np.c_[self._edge_lengths, self._edge_lengths, self._edge_lengths]
                )
        return self._edge_lengths
Example #30
0
    def area(self):
        if (getattr(self, '_area', None) is None or
            getattr(self, '_normals', None) is None):
            # Compute areas of cell faces
            if(self.dim == 2):
                xy = self.gridN
                A, B = utils.indexCube('AB', self.vnC+1, np.array([self.nNx,
                                       self.nCy]))
                edge1 = xy[B, :] - xy[A, :]
                normal1 = np.c_[edge1[:, 1], -edge1[:, 0]]
                area1 = length2D(edge1)
                A, D = utils.indexCube('AD', self.vnC+1, np.array([self.nCx,
                                       self.nNy]))
                # Note that we are doing A-D to make sure the normal points the
                # right way.
                # Think about it. Look at the picture. Normal points towards C
                # iff you do this.
                edge2 = xy[A, :] - xy[D, :]
                normal2 = np.c_[edge2[:, 1], -edge2[:, 0]]
                area2 = length2D(edge2)
                self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2)]
                self._normals = [normalize2D(normal1), normalize2D(normal2)]

            elif(self.dim == 3):

                A, E, F, B = utils.indexCube('AEFB', self.vnC+1, np.array(
                                             [self.nNx, self.nCy, self.nCz]))
                normal1, area1 = utils.faceInfo(self.gridN, A, E, F, B,
                                                average=False,
                                                normalizeNormals=False)

                A, D, H, E = utils.indexCube('ADHE', self.vnC+1, np.array(
                                             [self.nCx, self.nNy, self.nCz]))
                normal2, area2 = utils.faceInfo(self.gridN, A, D, H, E,
                                                average=False,
                                                normalizeNormals=False)

                A, B, C, D = utils.indexCube('ABCD', self.vnC+1, np.array(
                                             [self.nCx, self.nCy, self.nNz]))
                normal3, area3 = utils.faceInfo(self.gridN, A, B, C, D,
                                                average=False,
                                                normalizeNormals=False)

                self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2),
                                   utils.mkvc(area3)]
                self._normals = [normal1, normal2, normal3]
        return self._area
###############################################################################
# Run the long on-time simulation
# -------------------------------

t = time.time()
print('--- Running Long On-Time Simulation ---')

prob_ramp_on.mu = mu_model
fields = prob_ramp_on.fields(sigma)

print(" ... done. Elapsed time {}".format(time.time() - t))
print('\n')

# grab the last time-step in the simulation
b_ramp_on = utils.mkvc(fields[:, 'b', -1])

###############################################################################
# Compute Magnetostatic Fields from the step-off source
# -----------------------------------------------------

prob_magnetostatic.mu = mu_model
prob_magnetostatic.model = sigma
b_magnetostatic = src_magnetostatic.bInitial(prob_magnetostatic)


###############################################################################
# Plot the results
# -----------------------------------------------------

def plotBFieldResults(
    def test_permeable_sources(self):

        target_mur = self.target_mur
        target_l = self.target_l
        target_r = self.target_r
        sigma_back = self.sigma_back
        model_names = self.model_names
        mesh = self.mesh
        radius_loop = self.radius_loop

        # Assign physical properties on the mesh
        def populate_target(mur):
            mu_model = np.ones(mesh.nC)
            x_inds = mesh.gridCC[:, 0] < target_r
            z_inds = (
                (mesh.gridCC[:, 2] <= 0) & (mesh.gridCC[:, 2] >= -target_l)
            )
            mu_model[x_inds & z_inds] = mur
            return mu_0 * mu_model

        mu_dict = {
            key: populate_target(mu) for key, mu in
            zip(model_names, target_mur)
        }
        sigma = np.ones(mesh.nC) * sigma_back

        # Plot the models
        if plotIt:
            xlim = np.r_[-200, 200]  # x-limits in meters
            zlim = np.r_[-1.5*target_l, 10.]  # z-limits in meters. (z-positive up)

            fig, ax = plt.subplots(
                1, len(model_names), figsize=(6*len(model_names), 5)
            )
            if len(model_names) == 1:
                ax = [ax]

            for a, key in zip(ax, model_names):
                plt.colorbar(mesh.plotImage(
                    mu_dict[key], ax=a,
                    pcolorOpts={'norm': LogNorm()},  # plot on a log-scale
                    mirror=True
                )[0], ax=a)
                a.set_title('{}'.format(key), fontsize=13)
            #     cylMeshGen.mesh.plotGrid(ax=a, slice='theta') # uncomment to plot the mesh on top of this
                a.set_xlim(xlim)
                a.set_ylim(zlim)
            plt.tight_layout()
            plt.show()

        ramp = [
            (1e-5, 20), (1e-4, 20), (3e-4, 20), (1e-3, 20), (3e-3, 20),
            (1e-2, 20), (3e-2, 20), (1e-1, 20), (3e-1, 20), (1,  50)
        ]
        timeSteps = ramp

        time_mesh = discretize.TensorMesh([ramp])
        offTime = 10000
        waveform = TDEM.Src.QuarterSineRampOnWaveform(
            ramp_on=np.r_[1e-4, 20], ramp_off=offTime - np.r_[1e-4, 0]
        )

        if plotIt:
            wave = np.r_[[waveform.eval(t) for t in time_mesh.gridN]]
            plt.plot(time_mesh.gridN, wave)
            plt.plot(time_mesh.gridN, np.zeros(time_mesh.nN), '-|', color='k')
            plt.show()

        src_magnetostatic = TDEM.Src.CircularLoop(
            [], loc=np.r_[0., 0., 0.], orientation="z", radius=100,
        )

        src_ramp_on = TDEM.Src.CircularLoop(
            [], loc=np.r_[0., 0., 0.], orientation="z", radius=100,
            waveform=waveform
        )

        src_list = [src_magnetostatic]
        src_list_late_ontime = [src_ramp_on]

        prob = TDEM.Problem3D_b(
            mesh=mesh, timeSteps=timeSteps, sigmaMap=Maps.IdentityMap(mesh),
            Solver=Pardiso
        )
        prob_late_ontime = TDEM.Problem3D_b(
            mesh=mesh, timeSteps=timeSteps, sigmaMap=Maps.IdentityMap(mesh),
            Solver=Pardiso
        )

        survey = TDEM.Survey(srcList=src_list)
        survey_late_ontime = TDEM.Survey(src_list_late_ontime)

        prob.pair(survey)
        prob_late_ontime.pair(survey_late_ontime)

        fields_dict = {}

        for key in model_names:
            t = time.time()
            print('--- Running {} ---'.format(key))

            prob_late_ontime.mu = mu_dict[key]
            fields_dict[key] = prob_late_ontime.fields(sigma)

            print(" ... done. Elapsed time {}".format(time.time() - t))
            print('\n')

            b_magnetostatic = {}
            b_late_ontime = {}

        for key in model_names:
            prob.mu = mu_dict[key]
            prob.sigma = sigma
            b_magnetostatic[key] = src_magnetostatic.bInitial(prob)

            prob_late_ontime.mu = mu_dict[key]
            b_late_ontime[key] = utils.mkvc(
                fields_dict[key][:, 'b', -1]
            )

        if plotIt:
            fig, ax = plt.subplots(
                len(model_names), 2, figsize=(3*len(model_names), 5)
            )

            for i, key in enumerate(model_names):
                ax[i][0].semilogy(
                    np.absolute(b_magnetostatic[key]),
                    label='magnetostatic'
                )
                ax[i][0].semilogy(
                    np.absolute(b_late_ontime[key]), label='late on-time'
                )
                ax[i][0].legend()

                ax[i][1].semilogy(
                    np.absolute(b_magnetostatic[key] - b_late_ontime[key])
                )
            plt.tight_layout()
            plt.show()

        print("Testing TDEM with permeable targets")
        passed = []
        for key in model_names:
            norm_magneotstatic = np.linalg.norm(b_magnetostatic[key])
            norm_late_ontime = np.linalg.norm(b_late_ontime[key])
            norm_diff = np.linalg.norm(
                b_magnetostatic[key] - b_late_ontime[key]
            )
            passed_test = (
                norm_diff / (0.5*(norm_late_ontime + norm_magneotstatic))
                < TOL
            )
            print("\n{}".format(key))
            print(
                "||magnetostatic||: {:1.2e}, "
                "||late on-time||: {:1.2e}, "
                "||difference||: {:1.2e} passed?: {}".format(
                    norm_magneotstatic, norm_late_ontime, norm_diff,
                    passed_test
                )
            )

            passed += [passed_test]

        assert all(passed)

        prob.sigma = 1e-4*np.ones(mesh.nC)
        v = utils.mkvc(np.random.rand(mesh.nE))
        w = utils.mkvc(np.random.rand(mesh.nF))
        assert(
            np.all(
                mesh.getEdgeInnerProduct(1e-4*np.ones(mesh.nC))*v ==
                prob.MeSigma*v
            )
        )

        assert(
            np.all(
                mesh.getEdgeInnerProduct(
                    1e-4*np.ones(mesh.nC), invMat=True
                )*v ==
                prob.MeSigmaI*v
            )
        )
        assert(
            np.all(
                mesh.getFaceInnerProduct(1./1e-4*np.ones(mesh.nC))*w ==
                prob.MfRho*w
            )
        )

        assert(
            np.all(
                mesh.getFaceInnerProduct(
                    1./1e-4*np.ones(mesh.nC), invMat=True
                )*w ==
                prob.MfRhoI*w
            )
        )

        prob.rho = 1./1e-3*np.ones(mesh.nC)
        v = utils.mkvc(np.random.rand(mesh.nE))
        w = utils.mkvc(np.random.rand(mesh.nF))
        assert(
            np.all(
                mesh.getEdgeInnerProduct(1e-3*np.ones(mesh.nC))*v ==
                prob.MeSigma*v
            )
        )

        assert(
            np.all(
                mesh.getEdgeInnerProduct(
                    1e-3*np.ones(mesh.nC), invMat=True
                )*v ==
                prob.MeSigmaI*v
            )
        )
        assert(
            np.all(
                mesh.getFaceInnerProduct(1./1e-3*np.ones(mesh.nC))*w ==
                prob.MfRho*w
            )
        )

        assert(
            np.all(
                mesh.getFaceInnerProduct(
                    1./1e-3*np.ones(mesh.nC), invMat=True
                )*w ==
                prob.MfRhoI*w
            )
        )