Source code for fe_utils.mesh

from scipy.spatial import Delaunay
import numpy as np
import itertools
from .reference_elements import ReferenceTriangle, ReferenceInterval


[docs]class Mesh(object): """A one or two dimensional mesh composed of intervals or triangles respectively.""" def __init__(self, vertex_coords, cell_vertices): """ :param vertex_coords: a vertex_count x dim array of the coordinates of the vertices in the mesh. :param cell_vertices: a cell_count x (dim+1) array of the indices of the vertices of which each cell is made up. """ self.dim = vertex_coords.shape[1] """The geometric and topological dimension of the mesh. Immersed manifolds are not supported. """ if self.dim not in (1, 2): raise ValueError("Only 1D and 2D meshes are supported") self.vertex_coords = vertex_coords """The coordinates of all the vertices in the mesh.""" self.cell_vertices = np.sort(cell_vertices) """The indices of the vertices incident to cell.""" if self.dim == 2: self.edge_vertices = np.array( list(set(tuple(sorted(e)) for t in cell_vertices for e in itertools.combinations(t, 2))) ) """The indices of the vertices incident to edge (only for 2D meshes).""" # Invert self.edge_vertices so that it is possible to look up # the edge index given the vertex indices. edge_dict = {tuple(e): i for i, e_ in enumerate(self.edge_vertices) for e in (e_, reversed(e_))} # List the local vertex indices associated with # each local edge index. local_edge_vertices = np.array([[1, 2], [0, 2], [0, 1]]) self.cell_edges = np.fromiter( (edge_dict[tuple(t.take(local_edge_vertices[e]))] for t in self.cell_vertices for e in range(3)), dtype=np.int32, count=self.cell_vertices.size).reshape((-1, 3)) """The indices of the edges incident to each cell (only for 2D meshes).""" if self.dim == 2: self.entity_counts = np.array((vertex_coords.shape[0], self.edge_vertices.shape[0], self.cell_vertices.shape[0])) """The number of entities of each dimension in the mesh. So :attr:`entity_counts[0]` is the number of vertices in the mesh.""" else: self.entity_counts = np.array((vertex_coords.shape[0], self.cell_vertices.shape[0])) #: The :class:`~.reference_elements.ReferenceCell` of which this #: :class:`Mesh` is composed. self.cell = (0, ReferenceInterval, ReferenceTriangle)[self.dim]
[docs] def adjacency(self, dim1, dim2): """Return the set of `dim2` entities adjacent to each `dim1` entity. For example if `dim1==2` and `dim2==1` then return the list of edges (1D entities) adjacent to each triangle (2D entity). The return value is a rank 2 :class:`numpy.array` such that ``adjacency(dim1, dim2)[e1, :]`` is the list of dim2 entities adjacent to entity ``(dim1, e1)``. This operation is only defined where `self.dim >= dim1 > dim2`. This method is simply a more systematic way of accessing :attr:`edge_vertices`, :attr:`cell_edges` and :attr:`cell_vertices`. """ if dim2 >= dim1: raise ValueError("""dim2 must be less than dim1.""") if dim2 < 0: raise ValueError("""dim2 cannot be negative.""") if dim1 > self.dim: raise ValueError("""dim1 cannot exceed the mesh dimension.""") if dim1 == 1: if self.dim == 1: return self.cell_vertices else: return self.edge_vertices elif dim1 == 2: if dim2 == 0: return self.cell_vertices else: return self.cell_edges
[docs] def jacobian(self, c): """Return the Jacobian matrix for the specified cell. :param c: The number of the cell for which to return the Jacobian. :result: The Jacobian for cell ``c``. """ raise NotImplementedError
[docs]class UnitIntervalMesh(Mesh): """A mesh of the unit interval.""" def __init__(self, nx): """ :param nx: The number of cells. """ points = np.array(list((x,) for x in np.linspace(0, 1, nx + 1))) points.shape = (points.shape[0], 1) cells = np.array(list((a, a+1) for a in range(nx))) super(UnitIntervalMesh, self).__init__(points, cells)
[docs]class UnitSquareMesh(Mesh): """A triangulated :class:`Mesh` of the unit square.""" def __init__(self, nx, ny): """ :param nx: The number of cells in the x direction. :param ny: The number of cells in the y direction. """ points = list((x, y) for x in np.linspace(0, 1, nx + 1) for y in np.linspace(0, 1, ny + 1)) mesh = Delaunay(points) super(UnitSquareMesh, self).__init__(mesh.points, mesh.simplices)