Exemplo n.º 1
0
 def _needs_orientations(self, elements):
     for e in elements:
         cell = e.cell()
         if cell.topological_dimension() == cell.geometric_dimension():
             continue
         if isinstance(e, ufl.MixedElement) and e.family() != 'Real':
             if any("contravariant piola" in fiat_utils.fiat_from_ufl_element(s).mapping()
                    for s in e.sub_elements()):
                 return True
         else:
             if e.family() != 'Real' and \
                "contravariant piola" in fiat_utils.fiat_from_ufl_element(e).mapping():
                 return True
     return False
Exemplo n.º 2
0
 def _needs_orientations(self, elements):
     for e in elements:
         cell = e.cell()
         if cell.topological_dimension() == cell.geometric_dimension():
             continue
         if isinstance(e, ufl.MixedElement) and e.family() != 'Real':
             if any("contravariant piola" in
                    fiat_utils.fiat_from_ufl_element(s).mapping()
                    for s in e.sub_elements()):
                 return True
         else:
             if e.family() != 'Real' and \
                "contravariant piola" in fiat_utils.fiat_from_ufl_element(e).mapping():
                 return True
     return False
Exemplo n.º 3
0
def make_flat_fiat_element(ufl_cell_element, ufl_cell, flattened_entity_dofs):
    """Create a modified FIAT-style element.
    Transform object from 3D-Extruded to 2D-flattened FIAT-style object."""
    # Create base element
    base_element = fiat_utils.fiat_from_ufl_element(ufl_cell_element)

    # Alter base element
    base_element.dual.entity_ids = flattened_entity_dofs
    base_element.poly_set.num_members = total_num_dofs(flattened_entity_dofs)

    return base_element
Exemplo n.º 4
0
    def __init__(self, mesh, element, name=None, dim=1, rank=0):
        """
        :param mesh: :class:`Mesh` to build this space on
        :param element: :class:`ufl.FiniteElementBase` to build this space from
        :param name: user-defined name for this space
        :param dim: vector space dimension of a :class:`.VectorFunctionSpace`
        :param rank: rank of the space, not the value rank
        """

        self._ufl_element = element

        # Compute the FIAT version of the UFL element above
        self.fiat_element = fiat_utils.fiat_from_ufl_element(element)

        if isinstance(mesh, mesh_t.ExtrudedMesh):
            # Set up some extrusion-specific things
            # The bottom layer maps will come from element_dof_list
            # dof_count is the total number of dofs in the extruded mesh

            # Get the flattened version of the FIAT element
            self.flattened_element = fiat_utils.FlattenedElement(self.fiat_element)

            # Compute the number of DoFs per dimension on top/bottom and sides
            entity_dofs = self.fiat_element.entity_dofs()
            top_dim = mesh._plex.getDimension()
            self._xtr_hdofs = [len(entity_dofs[(d, 0)][0]) for d in range(top_dim+1)]
            self._xtr_vdofs = [len(entity_dofs[(d, 1)][0]) for d in range(top_dim+1)]

            # Compute the dofs per column
            self.dofs_per_column = eutils.compute_extruded_dofs(self.fiat_element,
                                                                self.flattened_element.entity_dofs(),
                                                                mesh._layers)

            # Compute the offset for the extrusion process
            self.offset = eutils.compute_offset(self.fiat_element.entity_dofs(),
                                                self.flattened_element.entity_dofs(),
                                                self.fiat_element.space_dimension())

            # Compute the top and bottom masks to identify boundary dofs
            #
            # Sorting the keys of the closure entity dofs, the whole cell
            # comes last [-1], before that the horizontal facet [-2], before
            # that vertical facets [-3]. We need the horizontal facets here.
            closure_dofs = self.fiat_element.entity_closure_dofs()
            b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0]
            t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1]
            self.bt_masks = {}
            self.bt_masks["topological"] = (b_mask, t_mask)  # conversion to tuple
            # Geometric facet dofs
            facet_dofs = horiz_facet_support_dofs(self.fiat_element)
            self.bt_masks["geometric"] = (facet_dofs[0], facet_dofs[1])

            self.extruded = True

            self._dofs_per_entity = self.dofs_per_column
        else:
            # If not extruded specific, set things to None/False, etc.
            self.offset = None
            self.bt_masks = None
            self.dofs_per_column = np.zeros(1, np.int32)
            self.extruded = False

            entity_dofs = self.fiat_element.entity_dofs()
            self._dofs_per_entity = [len(entity[0]) for d, entity in entity_dofs.iteritems()]

        self.name = name
        self._dim = dim
        self._mesh = mesh
        self._index = None

        dm = PETSc.DMShell().create()
        dm.setAttr('__fs__', weakref.ref(self))
        dm.setPointSF(mesh._plex.getPointSF())
        # Create the PetscSection mapping topological entities to DoFs
        sec = mesh._plex.createSection([1], self._dofs_per_entity,
                                       perm=mesh._plex_renumbering)
        dm.setDefaultSection(sec)
        self._global_numbering = sec
        self._dm = dm
        self._ises = None
        self._halo = halo.Halo(dm)

        # Compute entity class offsets
        self.dof_classes = [0, 0, 0, 0]
        for d in range(mesh._plex.getDimension()+1):
            ndofs = self._dofs_per_entity[d]
            for i in range(4):
                self.dof_classes[i] += ndofs * mesh._entity_classes[d, i]

        # Tell the DM about the layout of the global vector
        from firedrake.function import Function
        with Function(self).dat.vec_ro as v:
            self._dm.setGlobalVector(v.duplicate())

        self._node_count = self._global_numbering.getStorageSize()

        self.cell_node_list = mesh.create_cell_node_list(self._global_numbering,
                                                         self.fiat_element)

        if mesh._plex.getStratumSize("interior_facets", 1) > 0:
            self.interior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.interior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.interior_facet_node_list = np.array([], dtype=np.int32)

        if mesh._plex.getStratumSize("exterior_facets", 1) > 0:
            self.exterior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.exterior_facet_node_list = np.array([], dtype=np.int32)

        # Note: this is the function space rank. The value rank may be different.
        self.rank = rank

        # Empty map caches. This is a sui generis cache
        # implementation because of the need to support boundary
        # conditions.
        self._cell_node_map_cache = {}
        self._exterior_facet_map_cache = {}
        self._interior_facet_map_cache = {}
Exemplo n.º 5
0
    def __init__(self, mesh, element, name=None, dim=1, rank=0):
        """
        :param mesh: :class:`Mesh` to build this space on
        :param element: :class:`ufl.FiniteElementBase` to build this space from
        :param name: user-defined name for this space
        :param dim: vector space dimension of a :class:`.VectorFunctionSpace`
        :param rank: rank of the space, not the value rank
        """

        self._ufl_element = element

        # Compute the FIAT version of the UFL element above
        self.fiat_element = fiat_utils.fiat_from_ufl_element(element)

        if isinstance(mesh, mesh_t.ExtrudedMesh):
            # Set up some extrusion-specific things
            # The bottom layer maps will come from element_dof_list
            # dof_count is the total number of dofs in the extruded mesh

            # Get the flattened version of the FIAT element
            self.flattened_element = fiat_utils.FlattenedElement(
                self.fiat_element)

            # Compute the number of DoFs per dimension on top/bottom and sides
            entity_dofs = self.fiat_element.entity_dofs()
            top_dim = mesh._plex.getDimension()
            self._xtr_hdofs = [
                len(entity_dofs[(d, 0)][0]) for d in range(top_dim + 1)
            ]
            self._xtr_vdofs = [
                len(entity_dofs[(d, 1)][0]) for d in range(top_dim + 1)
            ]

            # Compute the dofs per column
            self.dofs_per_column = eutils.compute_extruded_dofs(
                self.fiat_element, self.flattened_element.entity_dofs(),
                mesh._layers)

            # Compute the offset for the extrusion process
            self.offset = eutils.compute_offset(
                self.fiat_element.entity_dofs(),
                self.flattened_element.entity_dofs(),
                self.fiat_element.space_dimension())

            # Compute the top and bottom masks to identify boundary dofs
            #
            # Sorting the keys of the closure entity dofs, the whole cell
            # comes last [-1], before that the horizontal facet [-2], before
            # that vertical facets [-3]. We need the horizontal facets here.
            closure_dofs = self.fiat_element.entity_closure_dofs()
            b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0]
            t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1]
            self.bt_masks = (b_mask, t_mask)  # conversion to tuple

            self.extruded = True

            self._dofs_per_entity = self.dofs_per_column
        else:
            # If not extruded specific, set things to None/False, etc.
            self.offset = None
            self.bt_masks = None
            self.dofs_per_column = np.zeros(1, np.int32)
            self.extruded = False

            entity_dofs = self.fiat_element.entity_dofs()
            self._dofs_per_entity = [
                len(entity[0]) for d, entity in entity_dofs.iteritems()
            ]

        self.name = name
        self._dim = dim
        self._mesh = mesh
        self._index = None

        dm = PETSc.DMShell().create()
        dm.setAttr('__fs__', weakref.ref(self))
        dm.setPointSF(mesh._plex.getPointSF())
        # Create the PetscSection mapping topological entities to DoFs
        sec = mesh._plex.createSection([1],
                                       self._dofs_per_entity,
                                       perm=mesh._plex_renumbering)
        dm.setDefaultSection(sec)
        self._global_numbering = sec
        self._dm = dm
        self._ises = None
        self._halo = halo.Halo(dm)

        # Compute entity class offsets
        self.dof_classes = [0, 0, 0, 0]
        for d in range(mesh._plex.getDimension() + 1):
            ndofs = self._dofs_per_entity[d]
            for i in range(4):
                self.dof_classes[i] += ndofs * mesh._entity_classes[d, i]

        # Tell the DM about the layout of the global vector
        from firedrake.function import Function
        with Function(self).dat.vec_ro as v:
            self._dm.setGlobalVector(v.duplicate())

        self._node_count = self._global_numbering.getStorageSize()

        self.cell_node_list = mesh.create_cell_node_list(
            self._global_numbering, self.fiat_element)

        if mesh._plex.getStratumSize("interior_facets", 1) > 0:
            self.interior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.interior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.interior_facet_node_list = np.array([], dtype=np.int32)

        if mesh._plex.getStratumSize("exterior_facets", 1) > 0:
            self.exterior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.exterior_facet_node_list = np.array([], dtype=np.int32)

        # Note: this is the function space rank. The value rank may be different.
        self.rank = rank

        # Empty map caches. This is a sui generis cache
        # implementation because of the need to support boundary
        # conditions.
        self._cell_node_map_cache = {}
        self._exterior_facet_map_cache = {}
        self._interior_facet_map_cache = {}
Exemplo n.º 6
0
    def __new__(cls, mesh, element, name=None, shape=()):
        """
        :param mesh: :class:`MeshTopology` to build this space on
        :param element: :class:`ufl.FiniteElementBase` to build this space from
        :param name: user-defined name for this space
        :param shape: shape of a :class:`.VectorFunctionSpace` or :class:`.TensorFunctionSpace`
        """

        assert mesh.ufl_cell() == element.cell()

        self = super(FunctionSpaceBase, cls).__new__(cls, mesh, element, name,
                                                     shape)
        if self._initialized:
            return self

        self._mesh = mesh
        self._ufl_element = element
        self.name = name
        self._shape = shape

        # Compute the FIAT version of the UFL element above
        self.fiat_element = fiat_utils.fiat_from_ufl_element(element)

        entity_dofs = self.fiat_element.entity_dofs()
        dofs_per_entity = mesh.make_dofs_per_plex_entity(entity_dofs)

        self.extruded = bool(mesh.layers)
        self.offset = mesh.make_offset(entity_dofs,
                                       self.fiat_element.space_dimension())

        if mesh.layers:
            # Compute the top and bottom masks to identify boundary dofs
            #
            # Sorting the keys of the closure entity dofs, the whole cell
            # comes last [-1], before that the horizontal facet [-2], before
            # that vertical facets [-3]. We need the horizontal facets here.
            closure_dofs = self.fiat_element.entity_closure_dofs()
            b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0]
            t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1]
            self.bt_masks = {}
            self.bt_masks["topological"] = (b_mask, t_mask
                                            )  # conversion to tuple
            # Geometric facet dofs
            facet_dofs = horiz_facet_support_dofs(self.fiat_element)
            self.bt_masks["geometric"] = (facet_dofs[0], facet_dofs[1])
        else:
            self.bt_masks = None

        dm = PETSc.DMShell().create()
        dm.setAttr('__fs__', weakref.ref(self))
        dm.setPointSF(mesh._plex.getPointSF())
        # Create the PetscSection mapping topological entities to DoFs
        sec = mesh._plex.createSection([1],
                                       dofs_per_entity,
                                       perm=mesh._plex_renumbering)
        dm.setDefaultSection(sec)
        self._global_numbering = sec
        self._dm = dm
        self._ises = None
        self._halo = halo.Halo(dm)

        # Compute entity class offsets
        self.dof_classes = [0, 0, 0, 0]
        for d in range(mesh._plex.getDimension() + 1):
            ndofs = dofs_per_entity[d]
            for i in range(4):
                self.dof_classes[i] += ndofs * mesh._entity_classes[d, i]

        # Tell the DM about the layout of the global vector
        with self.make_dat().vec_ro as v:
            self._dm.setGlobalVector(v.duplicate())

        self._node_count = self._global_numbering.getStorageSize()

        self.cell_node_list = mesh.make_cell_node_list(self._global_numbering,
                                                       entity_dofs)

        if mesh._plex.getStratumSize("interior_facets", 1) > 0:
            self.interior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.interior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.interior_facet_node_list = np.array([], dtype=np.int32)

        if mesh._plex.getStratumSize("exterior_facets", 1) > 0:
            self.exterior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.exterior_facet_node_list = np.array([], dtype=np.int32)

        # Empty map caches. This is a sui generis cache
        # implementation because of the need to support boundary
        # conditions.
        self._cell_node_map_cache = {}
        self._exterior_facet_map_cache = {}
        self._interior_facet_map_cache = {}

        self._initialized = True
        return self
Exemplo n.º 7
0
    def __new__(cls, mesh, element, name=None, shape=()):
        """
        :param mesh: :class:`MeshTopology` to build this space on
        :param element: :class:`ufl.FiniteElementBase` to build this space from
        :param name: user-defined name for this space
        :param shape: shape of a :class:`.VectorFunctionSpace` or :class:`.TensorFunctionSpace`
        """

        assert mesh.ufl_cell() == element.cell()

        self = super(FunctionSpaceBase, cls).__new__(cls, mesh, element, name, shape)
        if self._initialized:
            return self

        self._mesh = mesh
        self._ufl_element = element
        self.name = name
        self._shape = shape

        # Compute the FIAT version of the UFL element above
        self.fiat_element = fiat_utils.fiat_from_ufl_element(element)

        entity_dofs = self.fiat_element.entity_dofs()
        dofs_per_entity = mesh.make_dofs_per_plex_entity(entity_dofs)

        self.extruded = bool(mesh.layers)
        self.offset = mesh.make_offset(entity_dofs,
                                       self.fiat_element.space_dimension())

        if mesh.layers:
            # Compute the top and bottom masks to identify boundary dofs
            #
            # Sorting the keys of the closure entity dofs, the whole cell
            # comes last [-1], before that the horizontal facet [-2], before
            # that vertical facets [-3]. We need the horizontal facets here.
            closure_dofs = self.fiat_element.entity_closure_dofs()
            b_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][0]
            t_mask = closure_dofs[sorted(closure_dofs.keys())[-2]][1]
            self.bt_masks = {}
            self.bt_masks["topological"] = (b_mask, t_mask)  # conversion to tuple
            # Geometric facet dofs
            facet_dofs = horiz_facet_support_dofs(self.fiat_element)
            self.bt_masks["geometric"] = (facet_dofs[0], facet_dofs[1])
        else:
            self.bt_masks = None

        dm = PETSc.DMShell().create()
        dm.setAttr('__fs__', weakref.ref(self))
        dm.setPointSF(mesh._plex.getPointSF())
        # Create the PetscSection mapping topological entities to DoFs
        sec = mesh._plex.createSection([1], dofs_per_entity,
                                       perm=mesh._plex_renumbering)
        dm.setDefaultSection(sec)
        self._global_numbering = sec
        self._dm = dm
        self._ises = None
        self._halo = halo.Halo(dm)

        # Compute entity class offsets
        self.dof_classes = [0, 0, 0, 0]
        for d in range(mesh._plex.getDimension()+1):
            ndofs = dofs_per_entity[d]
            for i in range(4):
                self.dof_classes[i] += ndofs * mesh._entity_classes[d, i]

        # Tell the DM about the layout of the global vector
        with self.make_dat().vec_ro as v:
            self._dm.setGlobalVector(v.duplicate())

        self._node_count = self._global_numbering.getStorageSize()

        self.cell_node_list = mesh.make_cell_node_list(self._global_numbering,
                                                       entity_dofs)

        if mesh._plex.getStratumSize("interior_facets", 1) > 0:
            self.interior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.interior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.interior_facet_node_list = np.array([], dtype=np.int32)

        if mesh._plex.getStratumSize("exterior_facets", 1) > 0:
            self.exterior_facet_node_list = \
                dmplex.get_facet_nodes(mesh.exterior_facets.facet_cell,
                                       self.cell_node_list)
        else:
            self.exterior_facet_node_list = np.array([], dtype=np.int32)

        # Empty map caches. This is a sui generis cache
        # implementation because of the need to support boundary
        # conditions.
        self._cell_node_map_cache = {}
        self._exterior_facet_map_cache = {}
        self._interior_facet_map_cache = {}

        self._initialized = True
        return self
Exemplo n.º 8
0
    def __init__(self, mesh, layers, layer_height=None, extrusion_type='uniform', kernel=None, gdim=None):
        # A cache of function spaces that have been built on this mesh
        import firedrake.function as function
        import firedrake.functionspace as functionspace

        self._cache = {}
        mesh.init()
        self._old_mesh = mesh
        if layers < 1:
            raise RuntimeError("Must have at least one layer of extruded cells (not %d)" % layers)
        # All internal logic works with layers of base mesh (not layers of cells)
        self._layers = layers + 1
        self.parent = mesh.parent
        self.uid = mesh.uid
        self.name = mesh.name
        self._plex = mesh._plex
        self._plex_renumbering = mesh._plex_renumbering
        self._cell_numbering = mesh._cell_numbering
        self._entity_classes = mesh._entity_classes

        interior_f = self._old_mesh.interior_facets
        self._interior_facets = _Facets(self, interior_f.classes,
                                        "interior",
                                        interior_f.facet_cell,
                                        interior_f.local_facet_number)
        exterior_f = self._old_mesh.exterior_facets
        self._exterior_facets = _Facets(self, exterior_f.classes,
                                        "exterior",
                                        exterior_f.facet_cell,
                                        exterior_f.local_facet_number,
                                        exterior_f.markers,
                                        unique_markers=exterior_f.unique_markers)

        self.ufl_cell_element = ufl.FiniteElement("Lagrange",
                                                  domain=mesh.ufl_cell(),
                                                  degree=1)
        self.ufl_interval_element = ufl.FiniteElement("Lagrange",
                                                      domain=ufl.Cell("interval", 1),
                                                      degree=1)

        self.fiat_base_element = fiat_utils.fiat_from_ufl_element(self.ufl_cell_element)
        self.fiat_vert_element = fiat_utils.fiat_from_ufl_element(self.ufl_interval_element)

        fiat_element = FIAT.tensor_finite_element.TensorFiniteElement(self.fiat_base_element, self.fiat_vert_element)

        if extrusion_type == "uniform":
            # *must* add a new dimension
            self._ufl_cell = ufl.OuterProductCell(mesh.ufl_cell(), ufl.Cell("interval", 1), gdim=mesh.ufl_cell().geometric_dimension() + 1)

        elif extrusion_type in ("radial", "radial_hedgehog"):
            # do not allow radial extrusion if tdim = gdim
            if mesh.ufl_cell().geometric_dimension() == mesh.ufl_cell().topological_dimension():
                raise RuntimeError("Cannot radially-extrude a mesh with equal geometric and topological dimension")
            # otherwise, all is fine, so make cell
            self._ufl_cell = ufl.OuterProductCell(mesh.ufl_cell(), ufl.Cell("interval", 1))

        else:
            # check for kernel
            if kernel is None:
                raise RuntimeError("If the custom extrusion_type is used, a kernel must be provided")
            # otherwise, use the gdim that was passed in
            if gdim is None:
                raise RuntimeError("The geometric dimension of the mesh must be specified if a custom extrusion kernel is used")
            self._ufl_cell = ufl.OuterProductCell(mesh.ufl_cell(), ufl.Cell("interval", 1), gdim=gdim)

        self._ufl_domain = ufl.Domain(self.ufl_cell(), data=self)
        flat_temp = fiat_utils.FlattenedElement(fiat_element)

        # Calculated dofs_per_column from flattened_element and layers.
        # The mirrored elements have to be counted only once.
        # Then multiply by layers and layers - 1 accordingly.
        self.dofs_per_column = eutils.compute_extruded_dofs(fiat_element, flat_temp.entity_dofs(),
                                                            layers)

        # Compute Coordinates of the extruded mesh
        if layer_height is None:
            # Default to unit
            layer_height = 1.0 / layers

        if extrusion_type == 'radial_hedgehog':
            hfamily = "DG"
        else:
            hfamily = mesh.coordinates.element().family()
        hdegree = mesh.coordinates.element().degree()

        self._coordinate_fs = functionspace.VectorFunctionSpace(self, hfamily,
                                                                hdegree,
                                                                vfamily="CG",
                                                                vdegree=1)

        self.coordinates = function.Function(self._coordinate_fs)
        self._ufl_domain = ufl.Domain(self.coordinates)
        eutils.make_extruded_coords(self, layer_height, extrusion_type=extrusion_type,
                                    kernel=kernel)
        if extrusion_type == "radial_hedgehog":
            fs = functionspace.VectorFunctionSpace(self, "CG", hdegree, vfamily="CG", vdegree=1)
            self.radial_coordinates = function.Function(fs)
            eutils.make_extruded_coords(self, layer_height, extrusion_type="radial",
                                        output_coords=self.radial_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))
        self._ds_t = ufl.Measure('exterior_facet_top', subdomain_data=weakref.ref(self.coordinates))
        self._ds_b = ufl.Measure('exterior_facet_bottom', subdomain_data=weakref.ref(self.coordinates))
        self._ds_v = ufl.Measure('exterior_facet_vert', subdomain_data=weakref.ref(self.coordinates))
        self._dS_h = ufl.Measure('interior_facet_horiz', subdomain_data=weakref.ref(self.coordinates))
        self._dS_v = ufl.Measure('interior_facet_vert', 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.ds, ufl.dS, ufl.dx, ufl.ds_t, ufl.ds_b, ufl.ds_v, ufl.dS_h, ufl.dS_v]:
            measure._subdomain_data = weakref.ref(self.coordinates)
Exemplo n.º 9
0
    def __init__(self,
                 mesh,
                 layers,
                 layer_height=None,
                 extrusion_type='uniform',
                 kernel=None,
                 gdim=None):
        # A cache of function spaces that have been built on this mesh
        import firedrake.function as function
        import firedrake.functionspace as functionspace

        self._cache = {}
        mesh.init()
        self._old_mesh = mesh
        if layers < 1:
            raise RuntimeError(
                "Must have at least one layer of extruded cells (not %d)" %
                layers)
        # All internal logic works with layers of base mesh (not layers of cells)
        self._layers = layers + 1
        self.parent = mesh.parent
        self.uid = mesh.uid
        self.name = mesh.name
        self._plex = mesh._plex
        self._plex_renumbering = mesh._plex_renumbering
        self._cell_numbering = mesh._cell_numbering
        self._entity_classes = mesh._entity_classes

        interior_f = self._old_mesh.interior_facets
        self._interior_facets = _Facets(self, interior_f.classes, "interior",
                                        interior_f.facet_cell,
                                        interior_f.local_facet_number)
        exterior_f = self._old_mesh.exterior_facets
        self._exterior_facets = _Facets(
            self,
            exterior_f.classes,
            "exterior",
            exterior_f.facet_cell,
            exterior_f.local_facet_number,
            exterior_f.markers,
            unique_markers=exterior_f.unique_markers)

        self.ufl_cell_element = ufl.FiniteElement("Lagrange",
                                                  domain=mesh.ufl_cell(),
                                                  degree=1)
        self.ufl_interval_element = ufl.FiniteElement("Lagrange",
                                                      domain=ufl.Cell(
                                                          "interval", 1),
                                                      degree=1)

        self.fiat_base_element = fiat_utils.fiat_from_ufl_element(
            self.ufl_cell_element)
        self.fiat_vert_element = fiat_utils.fiat_from_ufl_element(
            self.ufl_interval_element)

        fiat_element = FIAT.tensor_finite_element.TensorFiniteElement(
            self.fiat_base_element, self.fiat_vert_element)

        if extrusion_type == "uniform":
            # *must* add a new dimension
            self._ufl_cell = ufl.OuterProductCell(
                mesh.ufl_cell(),
                ufl.Cell("interval", 1),
                gdim=mesh.ufl_cell().geometric_dimension() + 1)

        elif extrusion_type in ("radial", "radial_hedgehog"):
            # do not allow radial extrusion if tdim = gdim
            if mesh.ufl_cell().geometric_dimension() == mesh.ufl_cell(
            ).topological_dimension():
                raise RuntimeError(
                    "Cannot radially-extrude a mesh with equal geometric and topological dimension"
                )
            # otherwise, all is fine, so make cell
            self._ufl_cell = ufl.OuterProductCell(mesh.ufl_cell(),
                                                  ufl.Cell("interval", 1))

        else:
            # check for kernel
            if kernel is None:
                raise RuntimeError(
                    "If the custom extrusion_type is used, a kernel must be provided"
                )
            # otherwise, use the gdim that was passed in
            if gdim is None:
                raise RuntimeError(
                    "The geometric dimension of the mesh must be specified if a custom extrusion kernel is used"
                )
            self._ufl_cell = ufl.OuterProductCell(mesh.ufl_cell(),
                                                  ufl.Cell("interval", 1),
                                                  gdim=gdim)

        self._ufl_domain = ufl.Domain(self.ufl_cell(), data=self)
        flat_temp = fiat_utils.FlattenedElement(fiat_element)

        # Calculated dofs_per_column from flattened_element and layers.
        # The mirrored elements have to be counted only once.
        # Then multiply by layers and layers - 1 accordingly.
        self.dofs_per_column = eutils.compute_extruded_dofs(
            fiat_element, flat_temp.entity_dofs(), layers)

        # Compute Coordinates of the extruded mesh
        if layer_height is None:
            # Default to unit
            layer_height = 1.0 / layers

        if extrusion_type == 'radial_hedgehog':
            hfamily = "DG"
        else:
            hfamily = mesh.coordinates.element().family()
        hdegree = mesh.coordinates.element().degree()

        self._coordinate_fs = functionspace.VectorFunctionSpace(self,
                                                                hfamily,
                                                                hdegree,
                                                                vfamily="CG",
                                                                vdegree=1)

        self.coordinates = function.Function(self._coordinate_fs)
        self._ufl_domain = ufl.Domain(self.coordinates)
        eutils.make_extruded_coords(self,
                                    layer_height,
                                    extrusion_type=extrusion_type,
                                    kernel=kernel)
        if extrusion_type == "radial_hedgehog":
            fs = functionspace.VectorFunctionSpace(self,
                                                   "CG",
                                                   hdegree,
                                                   vfamily="CG",
                                                   vdegree=1)
            self.radial_coordinates = function.Function(fs)
            eutils.make_extruded_coords(self,
                                        layer_height,
                                        extrusion_type="radial",
                                        output_coords=self.radial_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))
        self._ds_t = ufl.Measure('exterior_facet_top',
                                 subdomain_data=weakref.ref(self.coordinates))
        self._ds_b = ufl.Measure('exterior_facet_bottom',
                                 subdomain_data=weakref.ref(self.coordinates))
        self._ds_v = ufl.Measure('exterior_facet_vert',
                                 subdomain_data=weakref.ref(self.coordinates))
        self._dS_h = ufl.Measure('interior_facet_horiz',
                                 subdomain_data=weakref.ref(self.coordinates))
        self._dS_v = ufl.Measure('interior_facet_vert',
                                 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.ds, ufl.dS, ufl.dx, ufl.ds_t, ufl.ds_b, ufl.ds_v, ufl.dS_h,
                ufl.dS_v
        ]:
            measure._subdomain_data = weakref.ref(self.coordinates)