Beispiel #1
0
def CubedSphereMesh(radius, refinement_level=0, degree=1,
                    reorder=None, use_dmplex_refinement=False,
                    comm=COMM_WORLD):
    """Generate an cubed approximation to the surface of the
    sphere.

    :arg radius: The radius of the sphere to approximate.
    :kwarg refinement_level: optional number of refinements (0 is a cube).
    :kwarg degree: polynomial degree of coordinate space (defaults
        to 1: bilinear quads)
    :kwarg reorder: (optional), should the mesh be reordered?
    :kwarg use_dmplex_refinement: (optional), use dmplex to apply
        the refinement.
    """
    if refinement_level < 0 or refinement_level % 1:
            raise RuntimeError("Number of refinements must be a non-negative integer")

    if degree < 1:
        raise ValueError("Mesh coordinate degree must be at least 1")

    cells, coords = _cubedsphere_cells_and_coords(radius, refinement_level)
    plex = mesh._from_cell_list(2, cells, coords, comm)

    m = mesh.Mesh(plex, dim=3, reorder=reorder)

    if degree > 1:
        new_coords = function.Function(functionspace.VectorFunctionSpace(m, "Q", degree))
        new_coords.interpolate(expression.Expression(("x[0]", "x[1]", "x[2]")))
        # "push out" to sphere
        new_coords.dat.data[:] *= (radius / np.linalg.norm(new_coords.dat.data, axis=1)).reshape(-1, 1)
        m = mesh.Mesh(new_coords)

    return m
Beispiel #2
0
def IcosahedralSphereMesh(radius, refinement_level=0, degree=1, reorder=None):
    """Generate an icosahedral approximation to the surface of the
    sphere.

    :arg radius: The radius of the sphere to approximate.
         For a radius R the edge length of the underlying
         icosahedron will be.

         .. math::

             a = \\frac{R}{\\sin(2 \\pi / 5)}

    :kwarg refinement_level: optional number of refinements (0 is an
        icosahedron).
    :kwarg degree: polynomial degree of coordinate space (defaults
        to 1: flat triangles)
    :kwarg reorder: (optional), should the mesh be reordered?
    """
    if degree < 1:
        raise ValueError("Mesh coordinate degree must be at least 1")
    from math import sqrt
    phi = (1 + sqrt(5)) / 2
    # vertices of an icosahedron with an edge length of 2
    vertices = np.array([[-1, phi, 0], [1, phi, 0], [-1, -phi,
                                                     0], [1, -phi, 0],
                         [0, -1, phi], [0, 1, phi], [0, -1,
                                                     -phi], [0, 1, -phi],
                         [phi, 0, -1], [phi, 0, 1], [-phi, 0, -1],
                         [-phi, 0, 1]])
    # faces of the base icosahedron
    faces = np.array(
        [[0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11], [1, 5, 9],
         [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8], [3, 9, 4], [3, 4, 2],
         [3, 2, 6], [3, 6, 8], [3, 8, 9], [4, 9, 5], [2, 4, 11], [6, 2, 10],
         [8, 6, 7], [9, 8, 1]],
        dtype=np.int32)

    plex = mesh._from_cell_list(2, faces, vertices)
    plex.setRefinementUniform(True)
    for i in range(refinement_level):
        plex = plex.refine()

    coords = plex.getCoordinatesLocal().array.reshape(-1, 3)
    scale = (radius / np.linalg.norm(coords, axis=1)).reshape(-1, 1)
    coords *= scale
    m = mesh.Mesh(plex, dim=3, reorder=reorder)
    if degree > 1:
        new_coords = function.Function(
            functionspace.VectorFunctionSpace(m, "CG", degree))
        new_coords.interpolate(expression.Expression(("x[0]", "x[1]", "x[2]")))
        # "push out" to sphere
        new_coords.dat.data[:] *= (
            radius / np.linalg.norm(new_coords.dat.data, axis=1)).reshape(
                -1, 1)
        m = mesh.Mesh(new_coords)
    m._icosahedral_sphere = radius
    return m
Beispiel #3
0
    def interpolate(self, expression, subset=None):
        """Interpolate an expression onto this :class:`Function`.

        :param expression: :class:`.Expression` to interpolate
        :returns: this :class:`Function` object"""

        # Make sure we have an expression of the right length i.e. a value for
        # each component in the value shape of each function space
        dims = [
            np.prod(fs.ufl_element().value_shape(), dtype=int)
            for fs in self.function_space()
        ]
        if np.prod(expression.value_shape(), dtype=int) != sum(dims):
            raise RuntimeError(
                'Expression of length %d required, got length %d' %
                (sum(dims), np.prod(expression.value_shape(), dtype=int)))

        if hasattr(expression, 'eval'):
            fs = self.function_space()
            if isinstance(fs, functionspace.MixedFunctionSpace):
                raise NotImplementedError(
                    "Python expressions for mixed functions are not yet supported."
                )
            self._interpolate(fs, self.dat, expression, subset)
        else:
            # Slice the expression and pass in the right number of values for
            # each component function space of this function
            d = 0
            for fs, dat, dim in zip(self.function_space(), self.dat, dims):
                idx = d if fs.rank == 0 else slice(d, d + dim)
                if fs.rank == 0:
                    code = expression.code[idx]
                else:
                    # Reshape so the sub-expression we build has the right shape.
                    code = expression.code[idx].reshape(
                        fs.ufl_element().value_shape())
                self._interpolate(
                    fs, dat, expression_t.Expression(code,
                                                     **expression._kwargs),
                    subset)
                d += dim
        return self
Beispiel #4
0
def CubedSphereMesh(radius, refinement_level=0, degree=1,
                    reorder=None, use_dmplex_refinement=False):
    """Generate an cubed approximation to the surface of the
    sphere.

    :arg radius: The radius of the sphere to approximate.
    :kwarg refinement_level: optional number of refinements (0 is a cube).
    :kwarg degree: polynomial degree of coordinate space (defaults
        to 1: bilinear quads)
    :kwarg reorder: (optional), should the mesh be reordered?
    :kwarg use_dmplex_refinement: (optional), use dmplex to apply
        the refinement.
    """
    if degree < 1:
        raise ValueError("Mesh coordinate degree must be at least 1")

    if use_dmplex_refinement:
        # vertices of a cube with an edge length of 2
        vertices = np.array([[-1., -1., -1.],
                             [1., -1., -1.],
                             [-1., 1., -1.],
                             [1., 1., -1.],
                             [-1., -1., 1.],
                             [1., -1., 1.],
                             [-1., 1., 1.],
                             [1., 1., 1.]])
        # faces of the base cube
        # bottom face viewed from above
        # 2 3
        # 0 1
        # top face viewed from above
        # 6 7
        # 4 5
        faces = np.array([[0, 1, 3, 2],  # bottom
                          [4, 5, 7, 6],  # top
                          [0, 1, 5, 4],
                          [2, 3, 7, 6],
                          [0, 2, 6, 4],
                          [1, 3, 7, 5]], dtype=np.int32)

        plex = mesh._from_cell_list(2, faces, vertices)
        plex.setRefinementUniform(True)
        for i in range(refinement_level):
            plex = plex.refine()

        # rescale points to the sphere
        # this is not the same as the gnonomic transformation
        coords = plex.getCoordinatesLocal().array.reshape(-1, 3)
        scale = (radius / np.linalg.norm(coords, axis=1)).reshape(-1, 1)
        coords *= scale
    else:
        cells, coords = _cubedsphere_cells_and_coords(radius, refinement_level)
        plex = mesh._from_cell_list(2, cells, coords)

    m = mesh.Mesh(plex, dim=3, reorder=reorder)

    if degree > 1:
        new_coords = function.Function(functionspace.VectorFunctionSpace(m, "Q", degree))
        new_coords.interpolate(expression.Expression(("x[0]", "x[1]", "x[2]")))
        # "push out" to sphere
        new_coords.dat.data[:] *= (radius / np.linalg.norm(new_coords.dat.data, axis=1)).reshape(-1, 1)
        m = mesh.Mesh(new_coords)

    return m