예제 #1
0
파일: mesh.py 프로젝트: hyharry/firedrake
 def __new__(cls, element):
     """Create mesh geometry object."""
     utils._init()
     mesh = super(MeshGeometry, cls).__new__(cls)
     mesh.uid = utils._new_uid()
     assert isinstance(element, ufl.FiniteElementBase)
     ufl.Mesh.__init__(mesh, element, ufl_id=mesh.uid)
     return mesh
예제 #2
0
    def __init__(self, value, domain=None):
        # Init also called in mesh constructor, but constant can be built without mesh
        utils._init()
        try:
            domain.init()
        except AttributeError:
            pass
        self.dat, rank, shape = _globalify(value)

        if rank == 0:
            e = ufl.FiniteElement("Real", domain, 0)
        elif rank == 1:
            e = ufl.VectorElement("Real", domain, 0, shape[0])
        elif rank == 2:
            e = ufl.TensorElement("Real", domain, 0, shape=shape)
        super(Constant, self).__init__(e)
        self._ufl_element = self.element()
        self._repr = 'Constant(%r, %r)' % (self._ufl_element, self.count())
예제 #3
0
    def __init__(self, value, domain=None):
        # Init also called in mesh constructor, but constant can be built without mesh
        utils._init()
        self.dat, rank, shape = _globalify(value)

        cell = None
        if domain is not None:
            domain = ufl.as_domain(domain)
            cell = domain.ufl_cell()
        if rank == 0:
            e = ufl.FiniteElement("Real", cell, 0)
        elif rank == 1:
            e = ufl.VectorElement("Real", cell, 0, shape[0])
        elif rank == 2:
            e = ufl.TensorElement("Real", cell, 0, shape=shape)

        fs = ufl.FunctionSpace(domain, e)
        super(Constant, self).__init__(fs)
        self._repr = 'Constant(%r, %r)' % (self.ufl_element(), self.count())
예제 #4
0
    def __init__(self, code=None, element=None, cell=None, degree=None, **kwargs):
        r"""
        C string expressions have now been removed from Firedrake, so passing ``code`` into this constructor will trigger an exception.
        :param kwargs: user-defined values that are accessible in the
                       Expression code.  These values maybe updated by
                       accessing the property of the same name.
        """
        # Init also called in mesh constructor, but expression can be built without mesh
        if code is not None:
            raise ValueError("C string Expressions have been removed! See: https://www.firedrakeproject.org/interpolation.html#c-string-expressions")
        utils._init()
        self._shape = ()
        self.cell = cell
        self.degree = degree
        # These attributes are required by ufl.Coefficient to render the repr
        # of an Expression. Since we don't call the ufl.Coefficient constructor
        # (since we don't yet know the element) we need to set them ourselves
        self._element = element
        self._repr = None
        self._count = 0

        self._user_args = []
        # Changing counter used to record when user changes values
        self._state = 0

        # Save the kwargs so that when we rebuild an expression we can
        # reconstruct the user arguments.
        self._kwargs = {}
        if len(kwargs) == 0:
            # No need for magic, since there are no user arguments.
            return

        # We have to build a new class to add these properties to
        # since properties work on classes not instances and we don't
        # want every Expression to have all the properties of all
        # Expressions.
        cls = type(self.__class__.__name__, (self.__class__, ), {})
        for slot, val in sorted(kwargs.items(), key=itemgetter(0)):
            # Save the argument for later reconstruction
            self._kwargs[slot] = val
            # Scalar arguments have to be treated specially
            val = np.array(val, dtype=np.float64)
            shape = val.shape
            rank = len(shape)
            if rank == 0:
                shape = 1
            val = op2.Global(shape, val, dtype=ScalarType, name=slot)
            # Record the Globals in a known order (for later passing
            # to a par_loop).  Remember their "name" too, so we can
            # construct a kwarg dict when applying python expressions.
            self._user_args.append((slot, val))
            # And save them as an attribute
            setattr(self, '_%s' % slot, val)

            # We have to do this because of the worthlessness of
            # Python's support for closing over variables.
            def make_getx(slot):
                def getx(self):
                    glob = getattr(self, '_%s' % slot)
                    return glob.data_ro
                return getx

            def make_setx(slot):
                def setx(self, value):
                    glob = getattr(self, '_%s' % slot)
                    glob.data = value
                    self._kwargs[slot] = value
                    # Bump state
                    self._state += 1
                return setx

            # Add public properties for the user-defined variables
            prop = property(make_getx(slot), make_setx(slot))
            setattr(cls, slot, prop)
        # Set the class on this instance to the newly built class with
        # properties attached.
        self.__class__ = cls
예제 #5
0
    def __init__(self, code=None, element=None, cell=None, degree=None, **kwargs):
        """
        :param code: a string C statement, or list of statements.
        :param element: a :class:`~ufl.finiteelement.finiteelement.FiniteElement`, optional
              (currently ignored)
        :param cell: a :class:`~ufl.classes.Cell`, optional (currently ignored)
        :param degree: the degree of quadrature to use for evaluation (currently ignored)
        :param kwargs: user-defined values that are accessible in the
               Expression code.  These values maybe updated by
               accessing the property of the same name.  This can be
               used, for example, to pass in the current timestep to
               an Expression without necessitating recompilation.  For
               example:

               .. code-block:: python

                  f = Function(V)
                  e = Expression('sin(x[0]*t)', t=t)
                  while t < T:
                      f.interpolate(e)
                      ...
                      t += dt
                      e.t = t

        The currently ignored parameters are retained for API compatibility with Dolfin.
        """
        # Init also called in mesh constructor, but expression can be built without mesh
        utils._init()
        self.code = None
        self._shape = ()
        if code is not None:
            arr = np.array(code)
            self._shape = arr.shape
            # Flatten to something indexable for use.
            self.code = arr.flatten()
            for val in self.code:
                if str(val).strip() == "":
                    raise ValueError("Cannot provide empty expression")
        self.cell = cell
        self.degree = degree
        # These attributes are required by ufl.Coefficient to render the repr
        # of an Expression. Since we don't call the ufl.Coefficient constructor
        # (since we don't yet know the element) we need to set them ourselves
        self._element = element
        self._repr = None
        self._count = 0

        self._user_args = []
        # Changing counter used to record when user changes values
        self._state = 0
        # Save the kwargs so that when we rebuild an expression we can
        # reconstruct the user arguments.
        self._kwargs = {}
        if len(kwargs) == 0:
            # No need for magic, since there are no user arguments.
            return

        # We have to build a new class to add these properties to
        # since properties work on classes not instances and we don't
        # want every Expression to have all the properties of all
        # Expressions.
        cls = type(self.__class__.__name__, (self.__class__, ), {})
        for slot, val in kwargs.iteritems():
            # Save the argument for later reconstruction
            self._kwargs[slot] = val
            # Scalar arguments have to be treated specially
            val = np.array(val, dtype=np.float64)
            shape = val.shape
            rank = len(shape)
            if rank == 0:
                shape = 1
            val = op2.Global(shape, val, dtype=np.float64, name=slot)
            # Record the Globals in a known order (for later passing
            # to a par_loop).  Remember their "name" too, so we can
            # construct a kwarg dict when applying python expressions.
            self._user_args.append((slot, val))
            # And save them as an attribute
            setattr(self, '_%s' % slot, val)

            # We have to do this because of the worthlessness of
            # Python's support for closing over variables.
            def make_getx(slot):
                def getx(self):
                    glob = getattr(self, '_%s' % slot)
                    return glob.data_ro
                return getx

            def make_setx(slot):
                def setx(self, value):
                    glob = getattr(self, '_%s' % slot)
                    glob.data = value
                    self._kwargs[slot] = value
                    # Bump state
                    self._state += 1
                return setx

            # Add public properties for the user-defined variables
            prop = property(make_getx(slot), make_setx(slot))
            setattr(cls, slot, prop)
        # Set the class on this instance to the newly built class with
        # properties attached.
        self.__class__ = cls
예제 #6
0
파일: mesh.py 프로젝트: hyharry/firedrake
def Mesh(meshfile, **kwargs):
    """Construct a mesh object.

    Meshes may either be created by reading from a mesh file, or by
    providing a PETSc DMPlex object defining the mesh topology.

    :param meshfile: Mesh file name (or DMPlex object) defining
           mesh topology.  See below for details on supported mesh
           formats.
    :param dim: optional specification of the geometric dimension
           of the mesh (ignored if not reading from mesh file).
           If not supplied the geometric dimension is deduced from
           the topological dimension of entities in the mesh.
    :param reorder: optional flag indicating whether to reorder
           meshes for better cache locality.  If not supplied the
           default value in ``parameters["reorder_meshes"]``
           is used.

    When the mesh is read from a file the following mesh formats
    are supported (determined, case insensitively, from the
    filename extension):

    * GMSH: with extension `.msh`
    * Exodus: with extension `.e`, `.exo`
    * CGNS: with extension `.cgns`
    * Triangle: with extension `.node`

    .. note::

        When the mesh is created directly from a DMPlex object,
        the ``dim`` parameter is ignored (the DMPlex already
        knows its geometric and topological dimensions).

    """
    import firedrake.functionspace as functionspace
    import firedrake.function as function

    if isinstance(meshfile, function.Function):
        coordinates = meshfile.topological
    elif isinstance(meshfile, function.CoordinatelessFunction):
        coordinates = meshfile
    else:
        coordinates = None

    if coordinates is not None:
        return make_mesh_from_coordinates(coordinates)

    utils._init()

    geometric_dim = kwargs.get("dim", None)
    reorder = kwargs.get("reorder", None)
    if reorder is None:
        reorder = parameters["reorder_meshes"]
    distribute = kwargs.get("distribute", True)

    if isinstance(meshfile, PETSc.DMPlex):
        name = "plexmesh"
        plex = meshfile
    else:
        name = meshfile
        basename, ext = os.path.splitext(meshfile)

        if ext.lower() in ['.e', '.exo']:
            plex = _from_exodus(meshfile)
        elif ext.lower() == '.cgns':
            plex = _from_cgns(meshfile)
        elif ext.lower() == '.msh':
            plex = _from_gmsh(meshfile)
        elif ext.lower() == '.node':
            plex = _from_triangle(meshfile, geometric_dim)
        else:
            raise RuntimeError("Mesh file %s has unknown format '%s'."
                               % (meshfile, ext[1:]))

    # Create mesh topology
    topology = MeshTopology(plex, name=name, reorder=reorder, distribute=distribute)

    tcell = topology.ufl_cell()
    if geometric_dim is None:
        geometric_dim = tcell.topological_dimension()
    cell = tcell.reconstruct(geometric_dimension=geometric_dim)

    element = ufl.VectorElement("Lagrange", cell, 1)
    # Create mesh object
    mesh = MeshGeometry.__new__(MeshGeometry, element)
    mesh._topology = topology

    def callback(self):
        """Finish initialisation."""
        del self._callback
        # Finish the initialisation of mesh topology
        self.topology.init()

        with timed_region("Mesh: coordinate field"):
            coordinates_fs = functionspace.VectorFunctionSpace(self.topology, "Lagrange", 1,
                                                               dim=geometric_dim)

            coordinates_data = dmplex.reordered_coords(plex, coordinates_fs._global_numbering,
                                                       (self.num_vertices(), geometric_dim))

            coordinates = function.CoordinatelessFunction(coordinates_fs,
                                                          val=coordinates_data,
                                                          name="Coordinates")

        self.__init__(coordinates)

    mesh._callback = callback
    return mesh
예제 #7
0
파일: mesh.py 프로젝트: hyharry/firedrake
    def __init__(self, plex, name, reorder, distribute):
        """Half-initialise a mesh topology.

        :arg plex: :class:`DMPlex` representing the mesh topology
        :arg name: name of the mesh
        :arg reorder: whether to reorder the mesh (bool)
        :arg distribute: whether to distribute the mesh to parallel processes
        """
        # Do some validation of the input mesh
        dmplex.validate_mesh(plex)
        utils._init()

        self._plex = plex
        self.name = name

        # A cache of function spaces that have been built on this mesh
        self._cache = {}

        # Mark exterior and interior facets
        # Note.  This must come before distribution, because otherwise
        # DMPlex will consider facets on the domain boundary to be
        # exterior, which is wrong.
        with timed_region("Mesh: label facets"):
            label_boundary = (op2.MPI.comm.size == 1) or distribute
            dmplex.label_facets(plex, label_boundary=label_boundary)

        # Distribute the dm to all ranks
        if op2.MPI.comm.size > 1 and distribute:
            # We distribute with overlap zero, in case we're going to
            # refine this mesh in parallel.  Later, when we actually use
            # it, we grow the halo.
            plex.distribute(overlap=0)

        dim = plex.getDimension()

        cStart, cEnd = plex.getHeightStratum(0)  # cells
        cell_nfacets = plex.getConeSize(cStart)

        self._grown_halos = False
        self._ufl_cell = ufl.Cell(_cells[dim][cell_nfacets])

        def callback(self):
            """Finish initialisation."""
            del self._callback
            if op2.MPI.comm.size > 1:
                self._plex.distributeOverlap(1)
            self._grown_halos = True

            if reorder:
                with timed_region("Mesh: reorder"):
                    old_to_new = self._plex.getOrdering(PETSc.Mat.OrderingType.RCM).indices
                    reordering = np.empty_like(old_to_new)
                    reordering[old_to_new] = np.arange(old_to_new.size, dtype=old_to_new.dtype)
            else:
                # No reordering
                reordering = None
            self._did_reordering = bool(reorder)

            # Mark OP2 entities and derive the resulting Plex renumbering
            with timed_region("Mesh: renumbering"):
                dmplex.mark_entity_classes(self._plex)
                self._entity_classes = dmplex.get_entity_classes(self._plex)
                self._plex_renumbering = dmplex.plex_renumbering(self._plex,
                                                                 self._entity_classes,
                                                                 reordering)

            with timed_region("Mesh: cell numbering"):
                # Derive a cell numbering from the Plex renumbering
                entity_dofs = np.zeros(dim+1, dtype=np.int32)
                entity_dofs[-1] = 1

                self._cell_numbering = self._plex.createSection([1], entity_dofs,
                                                                perm=self._plex_renumbering)
                entity_dofs[:] = 0
                entity_dofs[0] = 1
                self._vertex_numbering = self._plex.createSection([1], entity_dofs,
                                                                  perm=self._plex_renumbering)

        self._callback = callback
예제 #8
0
    def __init__(self, code=None, element=None, cell=None, degree=None, **kwargs):
        """
        :param code: a string C statement, or list of statements.
        :param element: a :class:`~ufl.finiteelement.finiteelement.FiniteElement`, optional
              (currently ignored)
        :param cell: a :class:`~ufl.classes.Cell`, optional (currently ignored)
        :param degree: the degree of quadrature to use for evaluation (currently ignored)
        :param kwargs: user-defined values that are accessible in the
               Expression code.  These values maybe updated by
               accessing the property of the same name.  This can be
               used, for example, to pass in the current timestep to
               an Expression without necessitating recompilation.  For
               example:

               .. code-block:: python

                  f = Function(V)
                  e = Expression('sin(x[0]*t)', t=t)
                  while t < T:
                      f.interpolate(e)
                      ...
                      t += dt
                      e.t = t

        The currently ignored parameters are retained for API compatibility with Dolfin.
        """
        # Init also called in mesh constructor, but expression can be built without mesh
        utils._init()
        self.code = None
        self._shape = ()
        if code is not None:
            arr = np.array(code)
            self._shape = arr.shape
            # Flatten to something indexable for use.
            self.code = arr.flatten()
        self.cell = cell
        self.degree = degree
        # These attributes are required by ufl.Coefficient to render the repr
        # of an Expression. Since we don't call the ufl.Coefficient constructor
        # (since we don't yet know the element) we need to set them ourselves
        self._element = element
        self._repr = None
        self._count = 0

        self._user_args = []
        # Changing counter used to record when user changes values
        self._state = 0
        # Save the kwargs so that when we rebuild an expression we can
        # reconstruct the user arguments.
        self._kwargs = {}
        if len(kwargs) == 0:
            # No need for magic, since there are no user arguments.
            return

        # We have to build a new class to add these properties to
        # since properties work on classes not instances and we don't
        # want every Expression to have all the properties of all
        # Expressions.
        cls = type(self.__class__.__name__, (self.__class__, ), {})
        for slot, val in kwargs.iteritems():
            # Save the argument for later reconstruction
            self._kwargs[slot] = val
            # Scalar arguments have to be treated specially
            val = np.array(val, dtype=np.float64)
            shape = val.shape
            rank = len(shape)
            if rank == 0:
                shape = 1
            val = op2.Global(shape, val, dtype=np.float64, name=slot)
            # Record the Globals in a known order (for later passing
            # to a par_loop).  Remember their "name" too, so we can
            # construct a kwarg dict when applying python expressions.
            self._user_args.append((slot, val))
            # And save them as an attribute
            setattr(self, '_%s' % slot, val)

            # We have to do this because of the worthlessness of
            # Python's support for closing over variables.
            def make_getx(slot):
                def getx(self):
                    glob = getattr(self, '_%s' % slot)
                    return glob.data_ro
                return getx

            def make_setx(slot):
                def setx(self, value):
                    glob = getattr(self, '_%s' % slot)
                    glob.data = value
                    self._kwargs[slot] = value
                    # Bump state
                    self._state += 1
                return setx

            # Add public properties for the user-defined variables
            prop = property(make_getx(slot), make_setx(slot))
            setattr(cls, slot, prop)
        # Set the class on this instance to the newly built class with
        # properties attached.
        self.__class__ = cls
예제 #9
0
    def __init__(self,
                 code=None,
                 element=None,
                 cell=None,
                 degree=None,
                 **kwargs):
        r"""
        C string expressions have now been removed from Firedrake, so passing ``code`` into this constructor will trigger an exception.
        :param kwargs: user-defined values that are accessible in the
                       Expression code.  These values maybe updated by
                       accessing the property of the same name.
        """
        # Init also called in mesh constructor, but expression can be built without mesh
        if code is not None:
            raise ValueError(
                "C string Expressions have been removed! See: https://www.firedrakeproject.org/interpolation.html#c-string-expressions"
            )
        utils._init()
        self._shape = ()
        self.cell = cell
        self.degree = degree
        # These attributes are required by ufl.Coefficient to render the repr
        # of an Expression. Since we don't call the ufl.Coefficient constructor
        # (since we don't yet know the element) we need to set them ourselves
        self._element = element
        self._repr = None
        self._count = 0

        self._user_args = []
        # Changing counter used to record when user changes values
        self._state = 0

        # Save the kwargs so that when we rebuild an expression we can
        # reconstruct the user arguments.
        self._kwargs = {}
        if len(kwargs) == 0:
            # No need for magic, since there are no user arguments.
            return

        # We have to build a new class to add these properties to
        # since properties work on classes not instances and we don't
        # want every Expression to have all the properties of all
        # Expressions.
        cls = type(self.__class__.__name__, (self.__class__, ), {})
        for slot, val in sorted(kwargs.items(), key=itemgetter(0)):
            # Save the argument for later reconstruction
            self._kwargs[slot] = val
            # Scalar arguments have to be treated specially
            val = np.array(val, dtype=utils.ScalarType)
            shape = val.shape
            rank = len(shape)
            if rank == 0:
                shape = 1
            val = op2.Global(shape, val, dtype=utils.ScalarType, name=slot)
            # Record the Globals in a known order (for later passing
            # to a par_loop).  Remember their "name" too, so we can
            # construct a kwarg dict when applying python expressions.
            self._user_args.append((slot, val))
            # And save them as an attribute
            setattr(self, '_%s' % slot, val)

            # We have to do this because of the worthlessness of
            # Python's support for closing over variables.
            def make_getx(slot):
                def getx(self):
                    glob = getattr(self, '_%s' % slot)
                    return glob.data_ro

                return getx

            def make_setx(slot):
                def setx(self, value):
                    glob = getattr(self, '_%s' % slot)
                    glob.data = value
                    self._kwargs[slot] = value
                    # Bump state
                    self._state += 1

                return setx

            # Add public properties for the user-defined variables
            prop = property(make_getx(slot), make_setx(slot))
            setattr(cls, slot, prop)
        # Set the class on this instance to the newly built class with
        # properties attached.
        self.__class__ = cls
예제 #10
0
파일: mesh.py 프로젝트: jychang48/firedrake
    def __init__(self, meshfile, **kwargs):
        """Construct a mesh object.

        Meshes may either be created by reading from a mesh file, or by
        providing a PETSc DMPlex object defining the mesh topology.

        :param meshfile: Mesh file name (or DMPlex object) defining
               mesh topology.  See below for details on supported mesh
               formats.
        :param dim: optional specification of the geometric dimension
               of the mesh (ignored if not reading from mesh file).
               If not supplied the geometric dimension is deduced from
               the topological dimension of entities in the mesh.
        :param reorder: optional flag indicating whether to reorder
               meshes for better cache locality.  If not supplied the
               default value in :data:`parameters["reorder_meshes"]`
               is used.
        :param periodic_coords: optional numpy array of coordinates
               used to replace those in the mesh object.  These are
               only supported in 1D and must have enough entries to be
               used as a DG1 field on the mesh.  Not supported when
               reading from file.

        When the mesh is read from a file the following mesh formats
        are supported (determined, case insensitively, from the
        filename extension):

        * GMSH: with extension `.msh`
        * Exodus: with extension `.e`, `.exo`
        * CGNS: with extension `.cgns`
        * Triangle: with extension `.node`

        .. note::

            When the mesh is created directly from a DMPlex object,
            the :data:`dim` parameter is ignored (the DMPlex already
            knows its geometric and topological dimensions).

        """

        utils._init()

        geometric_dim = kwargs.get("dim", None)
        reorder = kwargs.get("reorder", parameters["reorder_meshes"])
        periodic_coords = kwargs.get("periodic_coords", None)
        distribute = kwargs.get("distribute", True)

        if isinstance(meshfile, PETSc.DMPlex):
            name = "plexmesh"
            plex = meshfile
        else:
            name = meshfile
            basename, ext = os.path.splitext(meshfile)

            if periodic_coords is not None:
                raise RuntimeError("Periodic coordinates are unsupported when reading from file")
            if ext.lower() in ['.e', '.exo']:
                plex = _from_exodus(meshfile)
            elif ext.lower() == '.cgns':
                plex = _from_cgns(meshfile)
            elif ext.lower() == '.msh':
                plex = _from_gmsh(meshfile)
            elif ext.lower() == '.node':
                plex = _from_triangle(meshfile, geometric_dim)
            else:
                raise RuntimeError("Mesh file %s has unknown format '%s'."
                                   % (meshfile, ext[1:]))

        # Mark exterior and interior facets
        # Note.  This must come before distribution, because otherwise
        # DMPlex will consider facets on the domain boundary to be
        # exterior, which is wrong.
        with timed_region("Mesh: label facets"):
            label_boundary = op2.MPI.comm.size == 1 or distribute
            dmplex.label_facets(plex, label_boundary=label_boundary)

        # Distribute the dm to all ranks
        if op2.MPI.comm.size > 1 and distribute:
            # We distribute with overlap zero, in case we're going to
            # refine this mesh in parallel.  Later, when we actually use
            # it, we grow the halo.
            plex.distribute(overlap=0)

        # A cache of function spaces that have been built on this mesh
        self._cache = {}
        self.parent = None

        self.name = name
        self._plex = plex
        self.uid = utils._new_uid()

        topological_dim = self._plex.getDimension()
        if geometric_dim is None:
            geometric_dim = topological_dim

        cStart, cEnd = self._plex.getHeightStratum(0)  # cells
        cell_facets = self._plex.getConeSize(cStart)

        self._ufl_cell = ufl.Cell(fiat_utils._cells[topological_dim][cell_facets],
                                  geometric_dimension=geometric_dim)
        self._ufl_domain = ufl.Domain(self.ufl_cell(), data=self)
        self._grown_halos = False

        def callback(self):
            import firedrake.function as function
            import firedrake.functionspace as functionspace

            del self._callback
            if op2.MPI.comm.size > 1:
                self._plex.distributeOverlap(1)
            self._grown_halos = True

            if reorder:
                with timed_region("Mesh: reorder"):
                    old_to_new = self._plex.getOrdering(PETSc.Mat.OrderingType.RCM).indices
                    reordering = np.empty_like(old_to_new)
                    reordering[old_to_new] = np.arange(old_to_new.size, dtype=old_to_new.dtype)
            else:
                # No reordering
                reordering = None

            # Mark OP2 entities and derive the resulting Plex renumbering
            with timed_region("Mesh: renumbering"):
                dmplex.mark_entity_classes(self._plex)
                self._entity_classes = dmplex.get_entity_classes(self._plex)
                self._plex_renumbering = dmplex.plex_renumbering(self._plex,
                                                                 self._entity_classes,
                                                                 reordering)

            with timed_region("Mesh: cell numbering"):
                # Derive a cell numbering from the Plex renumbering
                entity_dofs = np.zeros(topological_dim+1, dtype=np.int32)
                entity_dofs[-1] = 1

                self._cell_numbering = self._plex.createSection([1], entity_dofs,
                                                                perm=self._plex_renumbering)
                entity_dofs[:] = 0
                entity_dofs[0] = 1
                self._vertex_numbering = self._plex.createSection([1], entity_dofs,
                                                                  perm=self._plex_renumbering)

            # Note that for bendy elements, this needs to change.
            with timed_region("Mesh: coordinate field"):
                if periodic_coords is not None:
                    if self.ufl_cell().geometric_dimension() != 1:
                        raise NotImplementedError("Periodic coordinates in more than 1D are unsupported")
                    # We've been passed a periodic coordinate field, so use that.
                    self._coordinate_fs = functionspace.VectorFunctionSpace(self, "DG", 1)
                    self.coordinates = function.Function(self._coordinate_fs,
                                                         val=periodic_coords,
                                                         name="Coordinates")
                else:
                    self._coordinate_fs = functionspace.VectorFunctionSpace(self, "Lagrange", 1)

                    coordinates = dmplex.reordered_coords(self._plex, self._coordinate_fs._global_numbering,
                                                          (self.num_vertices(), geometric_dim))
                    self.coordinates = function.Function(self._coordinate_fs,
                                                         val=coordinates,
                                                         name="Coordinates")
            self._ufl_domain = ufl.Domain(self.coordinates)
            # Build a new ufl element for this function space with the
            # correct domain.  This is necessary since this function space
            # is in the cache and will be picked up by later
            # VectorFunctionSpace construction.
            self._coordinate_fs._ufl_element = self._coordinate_fs.ufl_element().reconstruct(domain=self.ufl_domain())
            # HACK alert!
            # Replace coordinate Function by one that has a real domain on it (but don't copy values)
            self.coordinates = function.Function(self._coordinate_fs, val=self.coordinates.dat)
            # Add subdomain_data to the measure objects we store with
            # the mesh.  These are weakrefs for consistency with the
            # "global" measure objects
            self._dx = ufl.Measure('cell', subdomain_data=weakref.ref(self.coordinates))
            self._ds = ufl.Measure('exterior_facet', subdomain_data=weakref.ref(self.coordinates))
            self._dS = ufl.Measure('interior_facet', subdomain_data=weakref.ref(self.coordinates))
            # Set the subdomain_data on all the default measures to this
            # coordinate field.
            # We don't set the domain on the measure since this causes
            # an uncollectable reference in the global space (dx is
            # global).  Furthermore, it's never used anyway.
            for measure in [ufl.dx, ufl.ds, ufl.dS]:
                measure._subdomain_data = weakref.ref(self.coordinates)
        self._callback = callback
예제 #11
0
    def __init__(self, meshfile, **kwargs):
        """Construct a mesh object.

        Meshes may either be created by reading from a mesh file, or by
        providing a PETSc DMPlex object defining the mesh topology.

        :param meshfile: Mesh file name (or DMPlex object) defining
               mesh topology.  See below for details on supported mesh
               formats.
        :param dim: optional specification of the geometric dimension
               of the mesh (ignored if not reading from mesh file).
               If not supplied the geometric dimension is deduced from
               the topological dimension of entities in the mesh.
        :param reorder: optional flag indicating whether to reorder
               meshes for better cache locality.  If not supplied the
               default value in :data:`parameters["reorder_meshes"]`
               is used.
        :param periodic_coords: optional numpy array of coordinates
               used to replace those in the mesh object.  These are
               only supported in 1D and must have enough entries to be
               used as a DG1 field on the mesh.  Not supported when
               reading from file.

        When the mesh is read from a file the following mesh formats
        are supported (determined, case insensitively, from the
        filename extension):

        * GMSH: with extension `.msh`
        * Exodus: with extension `.e`, `.exo`
        * CGNS: with extension `.cgns`
        * Triangle: with extension `.node`

        .. note::

            When the mesh is created directly from a DMPlex object,
            the :data:`dim` parameter is ignored (the DMPlex already
            knows its geometric and topological dimensions).

        """

        utils._init()

        geometric_dim = kwargs.get("dim", None)
        reorder = kwargs.get("reorder", parameters["reorder_meshes"])
        periodic_coords = kwargs.get("periodic_coords", None)
        distribute = kwargs.get("distribute", True)

        if isinstance(meshfile, PETSc.DMPlex):
            name = "plexmesh"
            plex = meshfile
        else:
            name = meshfile
            basename, ext = os.path.splitext(meshfile)

            if periodic_coords is not None:
                raise RuntimeError(
                    "Periodic coordinates are unsupported when reading from file"
                )
            if ext.lower() in ['.e', '.exo']:
                plex = _from_exodus(meshfile)
            elif ext.lower() == '.cgns':
                plex = _from_cgns(meshfile)
            elif ext.lower() == '.msh':
                plex = _from_gmsh(meshfile)
            elif ext.lower() == '.node':
                plex = _from_triangle(meshfile, geometric_dim)
            else:
                raise RuntimeError("Mesh file %s has unknown format '%s'." %
                                   (meshfile, ext[1:]))

        # Mark exterior and interior facets
        # Note.  This must come before distribution, because otherwise
        # DMPlex will consider facets on the domain boundary to be
        # exterior, which is wrong.
        with timed_region("Mesh: label facets"):
            label_boundary = op2.MPI.comm.size == 1 or distribute
            dmplex.label_facets(plex, label_boundary=label_boundary)

        # Distribute the dm to all ranks
        if op2.MPI.comm.size > 1 and distribute:
            # We distribute with overlap zero, in case we're going to
            # refine this mesh in parallel.  Later, when we actually use
            # it, we grow the halo.
            plex.distribute(overlap=0)

        # A cache of function spaces that have been built on this mesh
        self._cache = {}
        self.parent = None

        self.name = name
        self._plex = plex
        self.uid = utils._new_uid()

        topological_dim = self._plex.getDimension()
        if geometric_dim is None:
            geometric_dim = topological_dim

        cStart, cEnd = self._plex.getHeightStratum(0)  # cells
        cell_facets = self._plex.getConeSize(cStart)

        self._ufl_cell = ufl.Cell(
            fiat_utils._cells[topological_dim][cell_facets],
            geometric_dimension=geometric_dim)
        self._ufl_domain = ufl.Domain(self.ufl_cell(), data=self)
        self._grown_halos = False

        def callback(self):
            import firedrake.function as function
            import firedrake.functionspace as functionspace

            del self._callback
            if op2.MPI.comm.size > 1:
                self._plex.distributeOverlap(1)
            self._grown_halos = True

            if reorder:
                with timed_region("Mesh: reorder"):
                    old_to_new = self._plex.getOrdering(
                        PETSc.Mat.OrderingType.RCM).indices
                    reordering = np.empty_like(old_to_new)
                    reordering[old_to_new] = np.arange(old_to_new.size,
                                                       dtype=old_to_new.dtype)
            else:
                # No reordering
                reordering = None

            # Mark OP2 entities and derive the resulting Plex renumbering
            with timed_region("Mesh: renumbering"):
                dmplex.mark_entity_classes(self._plex)
                self._entity_classes = dmplex.get_entity_classes(self._plex)
                self._plex_renumbering = dmplex.plex_renumbering(
                    self._plex, self._entity_classes, reordering)

            with timed_region("Mesh: cell numbering"):
                # Derive a cell numbering from the Plex renumbering
                entity_dofs = np.zeros(topological_dim + 1, dtype=np.int32)
                entity_dofs[-1] = 1

                self._cell_numbering = self._plex.createSection(
                    [1], entity_dofs, perm=self._plex_renumbering)
                entity_dofs[:] = 0
                entity_dofs[0] = 1
                self._vertex_numbering = self._plex.createSection(
                    [1], entity_dofs, perm=self._plex_renumbering)

            # Note that for bendy elements, this needs to change.
            with timed_region("Mesh: coordinate field"):
                if periodic_coords is not None:
                    if self.ufl_cell().geometric_dimension() != 1:
                        raise NotImplementedError(
                            "Periodic coordinates in more than 1D are unsupported"
                        )
                    # We've been passed a periodic coordinate field, so use that.
                    self._coordinate_fs = functionspace.VectorFunctionSpace(
                        self, "DG", 1)
                    self.coordinates = function.Function(self._coordinate_fs,
                                                         val=periodic_coords,
                                                         name="Coordinates")
                else:
                    self._coordinate_fs = functionspace.VectorFunctionSpace(
                        self, "Lagrange", 1)

                    coordinates = dmplex.reordered_coords(
                        self._plex, self._coordinate_fs._global_numbering,
                        (self.num_vertices(), geometric_dim))
                    self.coordinates = function.Function(self._coordinate_fs,
                                                         val=coordinates,
                                                         name="Coordinates")
            self._ufl_domain = ufl.Domain(self.coordinates)
            # Build a new ufl element for this function space with the
            # correct domain.  This is necessary since this function space
            # is in the cache and will be picked up by later
            # VectorFunctionSpace construction.
            self._coordinate_fs._ufl_element = self._coordinate_fs.ufl_element(
            ).reconstruct(domain=self.ufl_domain())
            # HACK alert!
            # Replace coordinate Function by one that has a real domain on it (but don't copy values)
            self.coordinates = function.Function(self._coordinate_fs,
                                                 val=self.coordinates.dat)
            # Add subdomain_data to the measure objects we store with
            # the mesh.  These are weakrefs for consistency with the
            # "global" measure objects
            self._dx = ufl.Measure('cell',
                                   subdomain_data=weakref.ref(
                                       self.coordinates))
            self._ds = ufl.Measure('exterior_facet',
                                   subdomain_data=weakref.ref(
                                       self.coordinates))
            self._dS = ufl.Measure('interior_facet',
                                   subdomain_data=weakref.ref(
                                       self.coordinates))
            # Set the subdomain_data on all the default measures to this
            # coordinate field.
            # We don't set the domain on the measure since this causes
            # an uncollectable reference in the global space (dx is
            # global).  Furthermore, it's never used anyway.
            for measure in [ufl.dx, ufl.ds, ufl.dS]:
                measure._subdomain_data = weakref.ref(self.coordinates)

        self._callback = callback
예제 #12
0
파일: mesh.py 프로젝트: jshipton/firedrake
def Mesh(meshfile, **kwargs):
    """Construct a mesh object.

    Meshes may either be created by reading from a mesh file, or by
    providing a PETSc DMPlex object defining the mesh topology.

    :param meshfile: Mesh file name (or DMPlex object) defining
           mesh topology.  See below for details on supported mesh
           formats.
    :param dim: optional specification of the geometric dimension
           of the mesh (ignored if not reading from mesh file).
           If not supplied the geometric dimension is deduced from
           the topological dimension of entities in the mesh.
    :param reorder: optional flag indicating whether to reorder
           meshes for better cache locality.  If not supplied the
           default value in ``parameters["reorder_meshes"]``
           is used.

    When the mesh is read from a file the following mesh formats
    are supported (determined, case insensitively, from the
    filename extension):

    * GMSH: with extension `.msh`
    * Exodus: with extension `.e`, `.exo`
    * CGNS: with extension `.cgns`
    * Triangle: with extension `.node`

    .. note::

        When the mesh is created directly from a DMPlex object,
        the ``dim`` parameter is ignored (the DMPlex already
        knows its geometric and topological dimensions).

    """
    import firedrake.functionspace as functionspace
    import firedrake.function as function

    if isinstance(meshfile, function.Function):
        coordinates = meshfile.topological
    elif isinstance(meshfile, function.CoordinatelessFunction):
        coordinates = meshfile
    else:
        coordinates = None

    if coordinates is not None:
        return make_mesh_from_coordinates(coordinates)

    utils._init()

    geometric_dim = kwargs.get("dim", None)
    reorder = kwargs.get("reorder", None)
    if reorder is None:
        reorder = parameters["reorder_meshes"]
    distribute = kwargs.get("distribute", True)

    if isinstance(meshfile, PETSc.DMPlex):
        name = "plexmesh"
        plex = meshfile
    else:
        name = meshfile
        basename, ext = os.path.splitext(meshfile)

        if ext.lower() in ['.e', '.exo']:
            plex = _from_exodus(meshfile)
        elif ext.lower() == '.cgns':
            plex = _from_cgns(meshfile)
        elif ext.lower() == '.msh':
            plex = _from_gmsh(meshfile)
        elif ext.lower() == '.node':
            plex = _from_triangle(meshfile, geometric_dim)
        else:
            raise RuntimeError("Mesh file %s has unknown format '%s'."
                               % (meshfile, ext[1:]))

    # Create mesh topology
    topology = MeshTopology(plex, name=name, reorder=reorder, distribute=distribute)

    tcell = topology.ufl_cell()
    if geometric_dim is None:
        geometric_dim = tcell.topological_dimension()
    cell = tcell.reconstruct(geometric_dimension=geometric_dim)

    element = ufl.VectorElement("Lagrange", cell, 1)
    # Create mesh object
    mesh = MeshGeometry.__new__(MeshGeometry, element)
    mesh._topology = topology

    def callback(self):
        """Finish initialisation."""
        del self._callback
        # Finish the initialisation of mesh topology
        self.topology.init()

        with timed_region("Mesh: coordinate field"):
            coordinates_fs = functionspace.VectorFunctionSpace(self.topology, "Lagrange", 1,
                                                               dim=geometric_dim)

            coordinates_data = dmplex.reordered_coords(plex, coordinates_fs._dm.getDefaultSection(),
                                                       (self.num_vertices(), geometric_dim))

            coordinates = function.CoordinatelessFunction(coordinates_fs,
                                                          val=coordinates_data,
                                                          name="Coordinates")

        self.__init__(coordinates)

    mesh._callback = callback
    return mesh