def test_prism_hcurl(space, degree, horiz_expected, vert_expected): W0_h = FIAT.Lagrange(UFCTriangle(), degree) W1_h = FIAT.supported_elements[space](UFCTriangle(), degree) W0_v = FIAT.DiscontinuousLagrange(UFCInterval(), degree - 1) W0 = FIAT.Hcurl(FIAT.TensorProductElement(W0_h, W0_v)) W1_v = FIAT.Lagrange(UFCInterval(), degree) W1 = FIAT.Hcurl(FIAT.TensorProductElement(W1_h, W1_v)) elem = FIAT.EnrichedElement(W0, W1) assert horiz_expected == entity_support_dofs(elem, (2, 0)) assert vert_expected == entity_support_dofs(elem, (1, 1))
def test_quad_rtcf(): W0_h = FIAT.Lagrange(UFCInterval(), 1) W1_h = FIAT.DiscontinuousLagrange(UFCInterval(), 0) W0_v = FIAT.DiscontinuousLagrange(UFCInterval(), 0) W0 = FIAT.Hdiv(FIAT.TensorProductElement(W0_h, W0_v)) W1_v = FIAT.Lagrange(UFCInterval(), 1) W1 = FIAT.Hdiv(FIAT.TensorProductElement(W1_h, W1_v)) elem = FIAT.EnrichedElement(W0, W1) assert {0: [0, 1, 2], 1: [0, 1, 3]} == entity_support_dofs(elem, (1, 0)) assert {0: [0, 2, 3], 1: [1, 2, 3]} == entity_support_dofs(elem, (0, 1))
def get_bt_masks(mesh, key, fiat_element): """Get masks for top and bottom dofs. :arg mesh: The mesh to use. :arg key: Canonicalised entity_dofs (see :func:`entity_dofs_key`). :arg fiat_element: The FIAT element. :returns: A dict mapping ``"topological"`` and ``"geometric"`` keys to bottom and top dofs (extruded) or ``None``. """ if not bool(mesh.layers): return None bt_masks = {} # 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 = fiat_element.entity_closure_dofs() horiz_facet_dim = sorted(closure_dofs.keys())[-2] b_mask = closure_dofs[horiz_facet_dim][0] t_mask = closure_dofs[horiz_facet_dim][1] bt_masks["topological"] = (b_mask, t_mask) # conversion to tuple # Geometric facet dofs facet_dofs = entity_support_dofs(fiat_element, horiz_facet_dim) bt_masks["geometric"] = (facet_dofs[0], facet_dofs[1]) return bt_masks
def test_discontinuous_element(): elem = FIAT.DiscontinuousElement(FIAT.Lagrange(UFCTriangle(), 3)) assert entity_support_dofs(elem, 1) == { 0: [1, 2, 3, 4], 1: [0, 2, 5, 6], 2: [0, 1, 7, 8] }
def test_hex(hex_mesh, args, kwargs, horiz_expected, vert_expected): V = FunctionSpace(hex_mesh, *args, **kwargs) assert horiz_expected == entity_support_dofs(V.fiat_element, (2, 0)) assert vert_expected == entity_support_dofs(V.fiat_element, (1, 1))
def exterior_facet_boundary_node_map(self, V, method): """Return the :class:`pyop2.Map` from exterior facets to nodes on the boundary. :arg V: The function space. :arg method: The method for determining boundary nodes. See :class:`~.DirichletBC` for details. """ try: return self.map_caches["boundary_node"][method] except KeyError: pass el = V.fiat_element dim = self.mesh.facet_dimension() if method == "topological": boundary_dofs = el.entity_closure_dofs()[dim] elif method == "geometric": # This function is only called on extruded meshes when # asking for the nodes that live on the "vertical" # exterior facets. boundary_dofs = entity_support_dofs(el, dim) nodes_per_facet = \ len(boundary_dofs[0]) # HACK ALERT # The facet set does not have a halo associated with it, since # we only construct halos for DoF sets. Fortunately, this # loop is direct and we already have all the correct # information available locally. So We fake a set of the # correct size and carry out a direct loop facet_set = op2.Set(self.mesh.exterior_facets.set.total_size, comm=self.mesh.comm) fs_dat = op2.Dat(facet_set**el.space_dimension(), data=V.exterior_facet_node_map().values_with_halo.view()) facet_dat = op2.Dat(facet_set**nodes_per_facet, dtype=numpy.int32) # Ensure these come out in sorted order. local_facet_nodes = numpy.array( [boundary_dofs[e] for e in sorted(boundary_dofs.keys())]) # Helper function to turn the inner index of an array into c # array literals. c_array = lambda xs: "{"+", ".join(map(str, xs))+"}" # AST for: l_nodes[facet[0]][n] rank_ast = ast.Symbol("l_nodes", rank=(ast.Symbol("facet", rank=(0,)), "n")) body = ast.Block([ast.Decl("int", ast.Symbol("l_nodes", (len(el.get_reference_element().topology[dim]), nodes_per_facet)), init=ast.ArrayInit(c_array(map(c_array, local_facet_nodes))), qualifiers=["const"]), ast.For(ast.Decl("int", "n", 0), ast.Less("n", nodes_per_facet), ast.Incr("n", 1), ast.Assign(ast.Symbol("facet_nodes", ("n",)), ast.Symbol("cell_nodes", (rank_ast, )))) ]) kernel = op2.Kernel(ast.FunDecl("void", "create_bc_node_map", [ast.Decl("int*", "cell_nodes"), ast.Decl("int*", "facet_nodes"), ast.Decl("unsigned int*", "facet")], body), "create_bc_node_map") local_facet_dat = op2.Dat(facet_set ** self.mesh.exterior_facets._rank, self.mesh.exterior_facets.local_facet_dat.data_ro_with_halos, dtype=numpy.uintc) op2.par_loop(kernel, facet_set, fs_dat(op2.READ), facet_dat(op2.WRITE), local_facet_dat(op2.READ)) if self.extruded: offset = self.offset[boundary_dofs[0]] else: offset = None val = op2.Map(facet_set, self.node_set, nodes_per_facet, facet_dat.data_ro_with_halos, name="exterior_facet_boundary_node", offset=offset) self.map_caches["boundary_node"][method] = val return val
def test_quad(base, extr, horiz_expected, vert_expected): elem_A = FIAT.supported_elements[base[0]](UFCInterval(), base[1]) elem_B = FIAT.supported_elements[extr[0]](UFCInterval(), extr[1]) elem = FIAT.TensorProductElement(elem_A, elem_B) assert horiz_expected == entity_support_dofs(elem, (1, 0)) assert vert_expected == entity_support_dofs(elem, (0, 1))
def exterior_facet_boundary_node_map(self, V, method): """Return the :class:`pyop2.Map` from exterior facets to nodes on the boundary. :arg V: The function space. :arg method: The method for determining boundary nodes. See :class:`~.DirichletBC` for details. """ try: return self.map_caches["boundary_node"][method] except KeyError: pass el = V.fiat_element dim = self.mesh.facet_dimension() if method == "topological": boundary_dofs = el.entity_closure_dofs()[dim] elif method == "geometric": # This function is only called on extruded meshes when # asking for the nodes that live on the "vertical" # exterior facets. boundary_dofs = entity_support_dofs(el, dim) nodes_per_facet = \ len(boundary_dofs[0]) # HACK ALERT # The facet set does not have a halo associated with it, since # we only construct halos for DoF sets. Fortunately, this # loop is direct and we already have all the correct # information available locally. So We fake a set of the # correct size and carry out a direct loop facet_set = op2.Set(self.mesh.exterior_facets.set.total_size, comm=self.mesh.comm) fs_dat = op2.Dat( facet_set**el.space_dimension(), data=V.exterior_facet_node_map().values_with_halo.view()) facet_dat = op2.Dat(facet_set**nodes_per_facet, dtype=numpy.int32) # Ensure these come out in sorted order. local_facet_nodes = numpy.array( [boundary_dofs[e] for e in sorted(boundary_dofs.keys())]) # Helper function to turn the inner index of an array into c # array literals. c_array = lambda xs: "{" + ", ".join(map(str, xs)) + "}" # AST for: l_nodes[facet[0]][n] rank_ast = ast.Symbol("l_nodes", rank=(ast.Symbol("facet", rank=(0, )), "n")) body = ast.Block([ ast.Decl("int", ast.Symbol("l_nodes", (len(el.get_reference_element().topology[dim]), nodes_per_facet)), init=ast.ArrayInit( c_array(map(c_array, local_facet_nodes))), qualifiers=["const"]), ast.For( ast.Decl("int", "n", 0), ast.Less("n", nodes_per_facet), ast.Incr("n", 1), ast.Assign(ast.Symbol("facet_nodes", ("n", )), ast.Symbol("cell_nodes", (rank_ast, )))) ]) kernel = op2.Kernel( ast.FunDecl("void", "create_bc_node_map", [ ast.Decl("int*", "cell_nodes"), ast.Decl("int*", "facet_nodes"), ast.Decl("unsigned int*", "facet") ], body), "create_bc_node_map") local_facet_dat = op2.Dat( facet_set**self.mesh.exterior_facets._rank, self.mesh.exterior_facets.local_facet_dat.data_ro_with_halos, dtype=numpy.uintc) op2.par_loop(kernel, facet_set, fs_dat(op2.READ), facet_dat(op2.WRITE), local_facet_dat(op2.READ)) if self.extruded: offset = self.offset[boundary_dofs[0]] else: offset = None val = op2.Map(facet_set, self.node_set, nodes_per_facet, facet_dat.data_ro_with_halos, name="exterior_facet_boundary_node", offset=offset) self.map_caches["boundary_node"][method] = val return val
def test_prism(base, extr, horiz_expected, vert_expected): elem_A = FIAT.supported_elements[base[0]](UFCTriangle(), base[1]) elem_B = FIAT.supported_elements[extr[0]](UFCInterval(), extr[1]) elem = FIAT.TensorProductElement(elem_A, elem_B) assert horiz_expected == entity_support_dofs(elem, (2, 0)) assert vert_expected == entity_support_dofs(elem, (1, 1))
def test_discontinuous_element(): elem = FIAT.DiscontinuousElement(FIAT.Lagrange(UFCTriangle(), 3)) assert entity_support_dofs(elem, 1) == {0: [1, 2, 3, 4], 1: [0, 2, 5, 6], 2: [0, 1, 7, 8]}