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
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
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 = {}
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 = {}
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
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
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)
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)