From 644c09bc61822ffeb723c5a8291c25794092e3ae Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Fri, 26 Apr 2024 17:41:55 +0100 Subject: [PATCH] Remove ufcx_dofmap and ufcx_element (#681) * branches * remove element and dofmap * basix main * fstrings * dolfinx main --- .../C/basix_custom_element_template.py | 39 --- ffcx/codegeneration/C/dofmap.py | 95 ------- ffcx/codegeneration/C/dofmap_template.py | 39 --- ffcx/codegeneration/C/expressions.py | 4 +- ffcx/codegeneration/C/finite_element.py | 232 ----------------- .../C/finite_element_template.py | 44 ---- ffcx/codegeneration/C/form.py | 19 +- ffcx/codegeneration/C/form_template.py | 2 - ffcx/codegeneration/C/integrals.py | 2 +- ffcx/codegeneration/codegeneration.py | 14 +- ffcx/codegeneration/jit.py | 88 ------- ffcx/codegeneration/ufcx.h | 185 +------------- ffcx/ir/analysis/graph.py | 2 +- ffcx/ir/analysis/reconstruct.py | 2 +- ffcx/ir/analysis/valuenumbering.py | 2 +- ffcx/ir/representation.py | 234 ++---------------- ffcx/naming.py | 22 +- test/test_blocked_elements.py | 122 --------- 18 files changed, 36 insertions(+), 1111 deletions(-) delete mode 100644 ffcx/codegeneration/C/basix_custom_element_template.py delete mode 100644 ffcx/codegeneration/C/dofmap.py delete mode 100644 ffcx/codegeneration/C/dofmap_template.py delete mode 100644 ffcx/codegeneration/C/finite_element.py delete mode 100644 ffcx/codegeneration/C/finite_element_template.py delete mode 100644 test/test_blocked_elements.py diff --git a/ffcx/codegeneration/C/basix_custom_element_template.py b/ffcx/codegeneration/C/basix_custom_element_template.py deleted file mode 100644 index b2e7d564f..000000000 --- a/ffcx/codegeneration/C/basix_custom_element_template.py +++ /dev/null @@ -1,39 +0,0 @@ -# Code generation format strings for UFC (Unified Form-assembly Code) -# This code is released into the public domain. -# -# The FEniCS Project (http://www.fenicsproject.org/) 2018. -"""Code generation strings for a Basix custom element.""" - -factory = """ -// Code for custom element {factory_name} - -{value_shape_init} -{wcoeffs_init} -{npts_init} -{ndofs_init} -{x_init} -{M_init} - -ufcx_basix_custom_finite_element {factory_name} = -{{ - .cell_type = {cell_type}, - .value_shape_length = {value_shape_length}, - .value_shape = {value_shape}, - .wcoeffs_rows = {wcoeffs_rows}, - .wcoeffs_cols = {wcoeffs_cols}, - .wcoeffs = {wcoeffs}, - .npts = {npts}, - .ndofs = {ndofs}, - .x = {x}, - .M = {M}, - .map_type = {map_type}, - .sobolev_space = {sobolev_space}, - .discontinuous = {discontinuous}, - .embedded_subdegree = {embedded_subdegree}, - .interpolation_nderivs = {interpolation_nderivs}, - .embedded_superdegree = {embedded_superdegree}, - .polyset_type = {polyset_type} -}}; - -// End of code for custom element {factory_name} -""" diff --git a/ffcx/codegeneration/C/dofmap.py b/ffcx/codegeneration/C/dofmap.py deleted file mode 100644 index a379f10f4..000000000 --- a/ffcx/codegeneration/C/dofmap.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2009-2018 Anders Logg, Martin Sandve Alnæs and Garth N. Wells -# -# This file is part of FFCx.(https://www.fenicsproject.org) -# -# SPDX-License-Identifier: LGPL-3.0-or-later -# -# Note: Most of the code in this file is a direct translation from the -# old implementation in FFC -"""Generate UFC code for a DOF map.""" - -import logging - -import ffcx.codegeneration.C.dofmap_template as ufcx_dofmap - -logger = logging.getLogger("ffcx") - - -def generator(ir, options): - """Generate UFC code for a dofmap.""" - logger.info("Generating code for dofmap:") - logger.info(f"--- num element support dofs: {ir.num_element_support_dofs}") - logger.info(f"--- name: {ir.name}") - - d = {} - - # Attributes - d["factory_name"] = ir.name - d["signature"] = f'"{ir.signature}"' - d["num_global_support_dofs"] = ir.num_global_support_dofs - d["num_element_support_dofs"] = ir.num_element_support_dofs - d["num_sub_dofmaps"] = ir.num_sub_dofmaps - - flattened_entity_dofs = [] - entity_dof_offsets = [0] - for dim in ir.entity_dofs: - for ent in dim: - for v in ent: - flattened_entity_dofs.append(v) - entity_dof_offsets.append(len(flattened_entity_dofs)) - d["entity_dofs"] = f"entity_dofs_{ir.name}" - values = ", ".join(str(i) for i in flattened_entity_dofs) - sizes = len(flattened_entity_dofs) - d["entity_dofs_init"] = f"int entity_dofs_{ir.name}[{sizes}] = {{{values}}};" - d["entity_dof_offsets"] = f"entity_dof_offsets_{ir.name}" - values = ", ".join(str(i) for i in entity_dof_offsets) - sizes = len(entity_dof_offsets) - d["entity_dof_offsets_init"] = f"int entity_dof_offsets_{ir.name}[{sizes}] = {{{values}}};" - - # Closure - flattened_entity_closure_dofs = [] - entity_closure_dof_offsets = [0] - for dim in ir.entity_closure_dofs: - for ent in dim: - for v in ent: - flattened_entity_closure_dofs.append(v) - entity_closure_dof_offsets.append(len(flattened_entity_closure_dofs)) - d["entity_closure_dofs"] = f"entity_closure_dofs_{ir.name}" - values = ", ".join(str(i) for i in flattened_entity_closure_dofs) - sizes = len(flattened_entity_closure_dofs) - d["entity_closure_dofs_init"] = f"int entity_closure_dofs_{ir.name}[{sizes}] = {{{values}}};" - d["entity_closure_dof_offsets"] = f"entity_closure_dof_offsets_{ir.name}" - values = ", ".join(str(i) for i in entity_closure_dof_offsets) - sizes = len(entity_dof_offsets) - d["entity_closure_dof_offsets_init"] = ( - f"int entity_closure_dof_offsets_{ir.name}[{sizes}] = {{{values}}};" - ) - - d["block_size"] = ir.block_size - - if len(ir.sub_dofmaps) > 0: - values = ", ".join(f"&{dofmap}" for dofmap in ir.sub_dofmaps) - sizes = len(ir.sub_dofmaps) - d["sub_dofmaps_initialization"] = ( - f"ufcx_dofmap* sub_dofmaps_{ir.name}[{sizes}] = {{{values}}};" - ) - d["sub_dofmaps"] = f"sub_dofmaps_{ir.name}" - else: - d["sub_dofmaps_initialization"] = "" - d["sub_dofmaps"] = "NULL" - - # Check that no keys are redundant or have been missed - from string import Formatter - - fields = [fname for _, fname, _, _ in Formatter().parse(ufcx_dofmap.factory) if fname] - # Remove square brackets from any field names - fields = [f.split("[")[0] for f in fields] - assert set(fields) == set(d.keys()), "Mismatch between keys in template and in formatting dict." - - # Format implementation code - implementation = ufcx_dofmap.factory.format_map(d) - - # Format declaration - declaration = ufcx_dofmap.declaration.format(factory_name=ir.name) - - return declaration, implementation diff --git a/ffcx/codegeneration/C/dofmap_template.py b/ffcx/codegeneration/C/dofmap_template.py deleted file mode 100644 index 38f54189d..000000000 --- a/ffcx/codegeneration/C/dofmap_template.py +++ /dev/null @@ -1,39 +0,0 @@ -# Code generation format strings for UFC (Unified Form-assembly Code) -# This code is released into the public domain. -# -# The FEniCS Project (http://www.fenicsproject.org/) 2018. -"""Code generation strings for a DOF map.""" - -declaration = """ -extern ufcx_dofmap {factory_name}; -""" - -factory = """ -// Code for dofmap {factory_name} - -{sub_dofmaps_initialization} - -{entity_dofs_init} - -{entity_dof_offsets_init} - -{entity_closure_dofs_init} - -{entity_closure_dof_offsets_init} - -ufcx_dofmap {factory_name} = -{{ - .signature = {signature}, - .num_global_support_dofs = {num_global_support_dofs}, - .num_element_support_dofs = {num_element_support_dofs}, - .block_size = {block_size}, - .entity_dofs = {entity_dofs}, - .entity_dof_offsets = {entity_dof_offsets}, - .entity_closure_dofs = {entity_closure_dofs}, - .entity_closure_dof_offsets = {entity_closure_dof_offsets}, - .num_sub_dofmaps = {num_sub_dofmaps}, - .sub_dofmaps = {sub_dofmaps} -}}; - -// End of code for dofmap {factory_name} -""" diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index ed461a0b4..60d7d07f6 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -108,7 +108,6 @@ def generator(ir, options): # ufcx_function_space is generated (also for ufcx_form) for name, ( element, - dofmap, cmap_family, cmap_degree, cmap_celltype, @@ -117,8 +116,7 @@ def generator(ir, options): ) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] - code += [f".finite_element = &{element},"] - code += [f".dofmap = &{dofmap},"] + code += [f".finite_element = {element},"] code += [f'.geometry_family = "{cmap_family}",'] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] diff --git a/ffcx/codegeneration/C/finite_element.py b/ffcx/codegeneration/C/finite_element.py deleted file mode 100644 index 7f3356562..000000000 --- a/ffcx/codegeneration/C/finite_element.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright (C) 2009-2022 Anders Logg, Martin Sandve Alnæs, Matthew Scroggs -# -# This file is part of FFCx.(https://www.fenicsproject.org) -# -# SPDX-License-Identifier: LGPL-3.0-or-later - -# Note: Much of the code in this file is a direct translation -# from the old implementation in FFC, although some improvements -# have been made to the generated code. -"""Generate UFC code for a finite element.""" - -import logging - -import ufl - -import ffcx.codegeneration.C.basix_custom_element_template as ufcx_basix_custom_finite_element -import ffcx.codegeneration.C.finite_element_template as ufcx_finite_element -import ffcx.codegeneration.C.quadrature_rule_template as ufcx_quadrature_rule - -logger = logging.getLogger("ffcx") -index_type = "int" - - -def generator(ir, options): - """Generate UFC code for a finite element.""" - logger.info("Generating code for finite element:") - logger.info(f"--- degree: {ir.degree}") - logger.info(f"--- value shape: {ir.reference_value_shape}") - logger.info(f"--- name: {ir.name}") - - d = {} - d["factory_name"] = ir.name - d["signature"] = f'"{ir.signature}"' - d["topological_dimension"] = ir.topological_dimension - d["cell_shape"] = ir.cell_shape - d["element_type"] = ir.element_type - d["space_dimension"] = ir.space_dimension - d["reference_value_rank"] = len(ir.reference_value_shape) - d["reference_value_size"] = ufl.product(ir.reference_value_shape) - d["degree"] = ir.degree - d["num_sub_elements"] = ir.num_sub_elements - d["block_size"] = ir.block_size - d["discontinuous"] = "true" if ir.discontinuous else "false" - d["symmetric"] = "true" if ir.symmetric else "false" - - if ir.lagrange_variant is None: - d["lagrange_variant"] = -1 - else: - d["lagrange_variant"] = int(ir.lagrange_variant) - - if ir.dpc_variant is None: - d["dpc_variant"] = -1 - else: - d["dpc_variant"] = int(ir.dpc_variant) - - if ir.basix_family is None: - d["basix_family"] = -1 - else: - d["basix_family"] = int(ir.basix_family) - if ir.basix_cell is None: - d["basix_cell"] = -1 - else: - d["basix_cell"] = int(ir.basix_cell) - - if len(ir.reference_value_shape) > 0: - d["reference_value_shape"] = f"reference_value_shape_{ir.name}" - values = ", ".join(str(i) for i in ir.reference_value_shape) - sizes = len(ir.reference_value_shape) - d["reference_value_shape_init"] = ( - f"int reference_value_shape_{ir.name}[{sizes}] = {{{values}}};" - ) - else: - d["reference_value_shape"] = "NULL" - d["reference_value_shape_init"] = "" - - if len(ir.sub_elements) > 0: - d["sub_elements"] = f"sub_elements_{ir.name}" - values = ", ".join(f"&{el}" for el in ir.sub_elements) - sizes = len(ir.sub_elements) - d["sub_elements_init"] = ( - f"ufcx_finite_element* sub_elements_{ir.name}[{sizes}] = {{{values}}};" - ) - else: - d["sub_elements"] = "NULL" - d["sub_elements_init"] = "" - - if ir.custom_element is not None: - d["custom_element"] = f"&custom_element_{ir.name}" - d["custom_element_init"] = generate_custom_element( - f"custom_element_{ir.name}", ir.custom_element - ) - else: - d["custom_element"] = "NULL" - d["custom_element_init"] = "" - - if ir.custom_quadrature is not None: - d["custom_quadrature"] = f"&custom_quadrature_{ir.name}" - d["custom_quadrature_init"] = generate_custom_quadrature( - f"custom_quadrature_{ir.name}", ir.custom_quadrature - ) - else: - d["custom_quadrature"] = "NULL" - d["custom_quadrature_init"] = "" - - # Check that no keys are redundant or have been missed - from string import Formatter - - fieldnames = [ - fname for _, fname, _, _ in Formatter().parse(ufcx_finite_element.factory) if fname - ] - assert set(fieldnames) == set( - d.keys() - ), "Mismatch between keys in template and in formatting dict" - - # Format implementation code - implementation = ufcx_finite_element.factory.format_map(d) - - # Format declaration - declaration = ufcx_finite_element.declaration.format(factory_name=ir.name) - - return declaration, implementation - - -def generate_custom_element(name, ir): - """Generate UFC code for a custom element.""" - d = {} - d["factory_name"] = name - d["cell_type"] = int(ir.cell_type) - d["polyset_type"] = int(ir.polyset_type) - d["map_type"] = int(ir.map_type) - d["sobolev_space"] = int(ir.sobolev_space) - d["embedded_subdegree"] = ir.embedded_subdegree - d["embedded_superdegree"] = ir.embedded_superdegree - d["discontinuous"] = "true" if ir.discontinuous else "false" - d["interpolation_nderivs"] = ir.interpolation_nderivs - d["value_shape_length"] = len(ir.value_shape) - if len(ir.value_shape) > 0: - d["value_shape"] = f"value_shape_{name}" - values = ", ".join(str(i) for i in ir.value_shape) - sizes = len(ir.value_shape) - d["value_shape_init"] = f"int value_shape_{name}[{sizes}] = {{{values}}};" - else: - d["value_shape"] = "NULL" - d["value_shape_init"] = "" - - d["wcoeffs_rows"] = ir.wcoeffs.shape[0] - d["wcoeffs_cols"] = ir.wcoeffs.shape[1] - d["wcoeffs"] = f"wcoeffs_{name}" - d["wcoeffs_init"] = f"double wcoeffs_{name}[{ir.wcoeffs.shape[0] * ir.wcoeffs.shape[1]}] = " - d["wcoeffs_init"] += "{" + ",".join([f" {i}" for row in ir.wcoeffs for i in row]) + "};" - - npts = [] - x = [] - for entity in ir.x: - for points in entity: - npts.append(points.shape[0]) - for row in points: - for i in row: - x.append(i) - d["npts"] = f"npts_{name}" - d["npts_init"] = f"int npts_{name}[{len(npts)}] = " - d["npts_init"] += "{" + ",".join([f" {i}" for i in npts]) + "};" - d["x"] = f"x_{name}" - d["x_init"] = f"double x_{name}[{len(x)}] = " - d["x_init"] += "{" + ",".join([f" {i}" for i in x]) + "};" - ndofs = [] - M = [] - for entity in ir.M: - for mat4d in entity: - ndofs.append(mat4d.shape[0]) - for mat3d in mat4d: - for mat2d in mat3d: - for row in mat2d: - for i in row: - M.append(i) - - d["ndofs"] = f"ndofs_{name}" - d["ndofs_init"] = f"int ndofs_{name}[{len(ndofs)}] = " - d["ndofs_init"] += "{" + ",".join([f" {i}" for i in ndofs]) + "};" - d["M"] = f"M_{name}" - d["M_init"] = f"double M_{name}[{len(M)}] = " - d["M_init"] += "{" + ",".join([f" {i}" for i in M]) + "};" - - # Check that no keys are redundant or have been missed - from string import Formatter - - fieldnames = [ - fname - for _, fname, _, _ in Formatter().parse(ufcx_basix_custom_finite_element.factory) - if fname - ] - assert set(fieldnames) == set( - d.keys() - ), "Mismatch between keys in template and in formatting dict" - - # Format implementation code - implementation = ufcx_basix_custom_finite_element.factory.format_map(d) - - return implementation - - -def generate_custom_quadrature(name, ir): - """Generate UFC code for a custom quadrature rule.""" - npts = ir.points.shape[0] - tdim = ir.points.shape[1] - - d = {} - d["factory_name"] = name - d["cell_shape"] = ir.cell_shape - d["topological_dimension"] = tdim - d["npts"] = npts - d["points"] = f"points_{name}" - d["points_init"] = f"double points_{name}[{npts * tdim}] = " - d["points_init"] += "{" + ",".join([f" {i}" for p in ir.points for i in p]) + "};" - d["weights"] = f"weights_{name}" - d["weights_init"] = f"double weights_{name}[{npts}] = " - d["weights_init"] += "{" + ",".join([f" {i}" for i in ir.weights]) + "};" - - # Check that no keys are redundant or have been missed - from string import Formatter - - fieldnames = [ - fname for _, fname, _, _ in Formatter().parse(ufcx_quadrature_rule.factory) if fname - ] - assert set(fieldnames) == set( - d.keys() - ), "Mismatch between keys in template and in formatting dict" - - # Format implementation code - implementation = ufcx_quadrature_rule.factory.format_map(d) - - return implementation diff --git a/ffcx/codegeneration/C/finite_element_template.py b/ffcx/codegeneration/C/finite_element_template.py deleted file mode 100644 index 6bf37a6aa..000000000 --- a/ffcx/codegeneration/C/finite_element_template.py +++ /dev/null @@ -1,44 +0,0 @@ -# Code generation format strings for UFC (Unified Form-assembly Code) -# This code is released into the public domain. -# -# The FEniCS Project (http://www.fenicsproject.org/) 2018. -"""Code generation strings for a finite element.""" - -declaration = """ -extern ufcx_finite_element {factory_name}; -""" - -factory = """ -// Code for element {factory_name} - -{reference_value_shape_init} -{sub_elements_init} -{custom_element_init} -{custom_quadrature_init} - -ufcx_finite_element {factory_name} = -{{ - .signature = {signature}, - .cell_shape = {cell_shape}, - .element_type = {element_type}, - .topological_dimension = {topological_dimension}, - .space_dimension = {space_dimension}, - .reference_value_rank = {reference_value_rank}, - .reference_value_shape = {reference_value_shape}, - .reference_value_size = {reference_value_size}, - .degree = {degree}, - .symmetric = {symmetric}, - .block_size = {block_size}, - .basix_family = {basix_family}, - .basix_cell = {basix_cell}, - .discontinuous = {discontinuous}, - .lagrange_variant = {lagrange_variant}, - .dpc_variant = {dpc_variant}, - .num_sub_elements = {num_sub_elements}, - .sub_elements = {sub_elements}, - .custom_element = {custom_element}, - .custom_quadrature = {custom_quadrature} -}}; - -// End of code for element {factory_name} -""" diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index 56747f909..6d02273b6 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -69,24 +69,13 @@ def generator(ir, options): if len(ir.finite_elements) > 0: d["finite_elements"] = f"finite_elements_{ir.name}" - values = ", ".join(f"&{el}" for el in ir.finite_elements) + values = ", ".join(f"{el}" for el in ir.finite_elements) sizes = len(ir.finite_elements) - d["finite_elements_init"] = ( - f"ufcx_finite_element* finite_elements_{ir.name}[{sizes}] = {{{values}}};" - ) + d["finite_elements_init"] = f"long int finite_elements_{ir.name}[{sizes}] = {{{values}}};" else: d["finite_elements"] = "NULL" d["finite_elements_init"] = "" - if len(ir.dofmaps) > 0: - d["dofmaps"] = f"dofmaps_{ir.name}" - values = ", ".join(f"&{dofmap}" for dofmap in ir.dofmaps) - sizes = len(ir.dofmaps) - d["dofmaps_init"] = f"ufcx_dofmap* dofmaps_{ir.name}[{sizes}] = {{{values}}};" - else: - d["dofmaps"] = "NULL" - d["dofmaps_init"] = "" - integrals = [] integral_ids = [] integral_offsets = [0] @@ -134,7 +123,6 @@ def generator(ir, options): # ufcx_function_space is generated for name, ( element, - dofmap, cmap_family, cmap_degree, cmap_celltype, @@ -143,8 +131,7 @@ def generator(ir, options): ) in ir.function_spaces.items(): code += [f"static ufcx_function_space functionspace_{name} ="] code += ["{"] - code += [f".finite_element = &{element},"] - code += [f".dofmap = &{dofmap},"] + code += [f".finite_element = {element},"] code += [f'.geometry_family = "{cmap_family}",'] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] diff --git a/ffcx/codegeneration/C/form_template.py b/ffcx/codegeneration/C/form_template.py index dfce2f14a..5e9cfbd5c 100644 --- a/ffcx/codegeneration/C/form_template.py +++ b/ffcx/codegeneration/C/form_template.py @@ -23,7 +23,6 @@ // Code for form {factory_name} {original_coefficient_position_init} -{dofmaps_init} {finite_elements_init} {form_integral_offsets_init} {form_integrals_init} @@ -45,7 +44,6 @@ .constant_name_map = {constant_names}, .finite_elements = {finite_elements}, - .dofmaps = {dofmaps}, .form_integrals = {form_integrals}, .form_integral_ids = {form_integral_ids}, diff --git a/ffcx/codegeneration/C/integrals.py b/ffcx/codegeneration/C/integrals.py index 58ab1c9b7..d301eceda 100644 --- a/ffcx/codegeneration/C/integrals.py +++ b/ffcx/codegeneration/C/integrals.py @@ -75,7 +75,7 @@ def generator(ir: IntegralIR, options): needs_facet_permutations="true" if ir.needs_facet_permutations else "false", scalar_type=dtype_to_c_type(options["scalar_type"]), geom_type=dtype_to_c_type(dtype_to_scalar_dtype(options["scalar_type"])), - coordinate_element=f"&{ir.coordinate_element}", + coordinate_element=f"{ir.coordinate_element}", tabulate_tensor_float32=code["tabulate_tensor_float32"], tabulate_tensor_float64=code["tabulate_tensor_float64"], tabulate_tensor_complex64=code["tabulate_tensor_complex64"], diff --git a/ffcx/codegeneration/codegeneration.py b/ffcx/codegeneration/codegeneration.py index 9f573b703..9564c3837 100644 --- a/ffcx/codegeneration/codegeneration.py +++ b/ffcx/codegeneration/codegeneration.py @@ -17,10 +17,8 @@ import numpy.typing as npt -from ffcx.codegeneration.C.dofmap import generator as dofmap_generator from ffcx.codegeneration.C.expressions import generator as expression_generator from ffcx.codegeneration.C.file import generator as file_generator -from ffcx.codegeneration.C.finite_element import generator as finite_element_generator from ffcx.codegeneration.C.form import generator as form_generator from ffcx.codegeneration.C.integrals import generator as integral_generator from ffcx.ir.representation import DataIR @@ -31,13 +29,10 @@ class CodeBlocks(typing.NamedTuple): """Storage of code blocks of the form (declaration, implementation). - Blocks for elements, dofmaps, integrals, forms and expressions, - and start and end of file output + Blocks for integrals, forms and expressions, and start and end of file output """ file_pre: list[tuple[str, str]] - elements: list[tuple[str, str]] - dofmaps: list[tuple[str, str]] integrals: list[tuple[str, str]] forms: list[tuple[str, str]] expressions: list[tuple[str, str]] @@ -50,11 +45,6 @@ def generate_code(ir: DataIR, options: dict[str, int | float | npt.DTypeLike]) - logger.info("Compiler stage 3: Generating code") logger.info(79 * "*") - # Generate code for finite_elements - code_finite_elements = [ - finite_element_generator(element_ir, options) for element_ir in ir.elements - ] - code_dofmaps = [dofmap_generator(dofmap_ir, options) for dofmap_ir in ir.dofmaps] code_integrals = [integral_generator(integral_ir, options) for integral_ir in ir.integrals] code_forms = [form_generator(form_ir, options) for form_ir in ir.forms] code_expressions = [ @@ -63,8 +53,6 @@ def generate_code(ir: DataIR, options: dict[str, int | float | npt.DTypeLike]) - code_file_pre, code_file_post = file_generator(options) return CodeBlocks( file_pre=[code_file_pre], - elements=code_finite_elements, - dofmaps=code_dofmaps, integrals=code_integrals, forms=code_forms, expressions=code_expressions, diff --git a/ffcx/codegeneration/jit.py b/ffcx/codegeneration/jit.py index d63f92800..aa903c496 100644 --- a/ffcx/codegeneration/jit.py +++ b/ffcx/codegeneration/jit.py @@ -20,7 +20,6 @@ import cffi import numpy as np -import numpy.typing as npt import ffcx import ffcx.naming @@ -38,12 +37,6 @@ header = header.replace("{", "{{").replace("}", "}}") UFC_HEADER_DECL = header + "\n" -UFC_ELEMENT_DECL = "\n".join( - re.findall("typedef struct ufcx_finite_element.*?ufcx_finite_element;", ufcx_h, re.DOTALL) -) -UFC_DOFMAP_DECL = "\n".join( - re.findall("typedef struct ufcx_dofmap.*?ufcx_dofmap;", ufcx_h, re.DOTALL) -) UFC_FORM_DECL = "\n".join(re.findall("typedef struct ufcx_form.*?ufcx_form;", ufcx_h, re.DOTALL)) UFC_INTEGRAL_DECL = "\n".join( @@ -133,83 +126,6 @@ def _compilation_signature(cffi_extra_compile_args=None, cffi_debug=None): ) -def compile_elements( - elements, - options: dict[str, int | float | npt.DTypeLike] | None = None, - cache_dir=None, - timeout=10, - cffi_extra_compile_args=None, - cffi_verbose=False, - cffi_debug=None, - cffi_libraries=None, - visualise: bool = False, -): - """Compile a list of UFL elements and dofmaps into Python objects.""" - p = ffcx.options.get_options(options) - - # Get a signature for these elements - module_name = "libffcx_elements_" + ffcx.naming.compute_signature( - elements, - _compute_option_signature(p) + _compilation_signature(cffi_extra_compile_args, cffi_debug), - ) - - names = [] - for e in elements: - name = ffcx.naming.finite_element_name(e, module_name) - names.append(name) - name = ffcx.naming.dofmap_name(e, module_name) - names.append(name) - - if cache_dir is not None: - cache_dir = Path(cache_dir) - obj, mod = get_cached_module(module_name, names, cache_dir, timeout) - if obj is not None: - # Pair up elements with dofmaps - obj = list(zip(obj[::2], obj[1::2])) - return obj, mod, (None, None) - else: - cache_dir = Path(tempfile.mkdtemp()) - - try: - decl = ( - UFC_HEADER_DECL.format(np.dtype(p["scalar_type"]).name) # type: ignore - + UFC_ELEMENT_DECL - + UFC_DOFMAP_DECL - ) - element_template = "extern ufcx_finite_element {name};\n" - dofmap_template = "extern ufcx_dofmap {name};\n" - for i in range(len(elements)): - decl += element_template.format(name=names[i * 2]) - decl += dofmap_template.format(name=names[i * 2 + 1]) - - impl = _compile_objects( - decl, - elements, - names, - module_name, - p, - cache_dir, - cffi_extra_compile_args, - cffi_verbose, - cffi_debug, - cffi_libraries, - visualise=visualise, - ) - except Exception as e: - try: - # remove c file so that it will not timeout next time - c_filename = cache_dir.joinpath(module_name + ".c") - os.replace(c_filename, c_filename.with_suffix(".c.failed")) - except Exception: - pass - raise e - - objects, module = _load_objects(cache_dir, module_name, names) - # Pair up elements with dofmaps - objects = list(zip(objects[::2], objects[1::2])) - return objects, module, (decl, impl) - - def compile_forms( forms, options=None, @@ -243,8 +159,6 @@ def compile_forms( try: decl = ( UFC_HEADER_DECL.format(np.dtype(p["scalar_type"]).name) # type: ignore - + UFC_ELEMENT_DECL - + UFC_DOFMAP_DECL + UFC_INTEGRAL_DECL + UFC_FORM_DECL ) @@ -324,8 +238,6 @@ def compile_expressions( try: decl = ( UFC_HEADER_DECL.format(np.dtype(p["scalar_type"]).name) # type: ignore - + UFC_ELEMENT_DECL - + UFC_DOFMAP_DECL + UFC_INTEGRAL_DECL + UFC_FORM_DECL + UFC_EXPRESSION_DECL diff --git a/ffcx/codegeneration/ufcx.h b/ffcx/codegeneration/ufcx.h index 7231b4b84..1851d5c03 100644 --- a/ffcx/codegeneration/ufcx.h +++ b/ffcx/codegeneration/ufcx.h @@ -60,144 +60,12 @@ extern "C" interior_facet = 2 } ufcx_integral_type; - typedef enum - { - ufcx_basix_element = 0, - ufcx_mixed_element = 1, - ufcx_quadrature_element = 2, - ufcx_basix_custom_element = 3, - ufcx_real_element = 4, - } ufcx_element_type; - /// Forward declarations - typedef struct ufcx_finite_element ufcx_finite_element; - typedef struct ufcx_basix_custom_finite_element ufcx_basix_custom_finite_element; typedef struct ufcx_quadrature_rule ufcx_quadrature_rule; - typedef struct ufcx_dofmap ufcx_dofmap; typedef struct ufcx_function_space ufcx_function_space; // - typedef struct ufcx_finite_element - { - /// String identifying the finite element - const char* signature; - - /// Cell shape - ufcx_shape cell_shape; - - /// Element type - ufcx_element_type element_type; - - /// Topological dimension of the cell - int topological_dimension; - - /// Dimension of the finite element function space - int space_dimension; - - /// Rank of the reference value space - int reference_value_rank; - - /// Dimension of the reference value space for axis i - int* reference_value_shape; - - /// Number of components of the reference value space - int reference_value_size; - - /// Maximum polynomial degree of the finite element function space - int degree; - - /// Is the value a symmetric 2-tensor - bool symmetric; - - /// Block size for a VectorElement. For a TensorElement, this is the - /// product of the tensor's dimensions - int block_size; - - /// Basix identifier of the family of the finite element function space - int basix_family; - - /// Basix identifier of the cell shape - int basix_cell; - - /// Indicates whether or not this is the discontinuous version of the element - bool discontinuous; - - /// The Lagrange variant to be passed to Basix's create_element function - int lagrange_variant; - - /// The DPC variant to be passed to Basix's create_element function - int dpc_variant; - - /// Number of sub elements (for a mixed element) - int num_sub_elements; - - /// Get a finite element for sub element i (for a mixed - /// element). - ufcx_finite_element** sub_elements; - - /// Pointer to data to recreate the element if it is a custom Basix element - ufcx_basix_custom_finite_element* custom_element; - - /// Pointer to data to recreate the custom quadrature rule if the element has one - ufcx_quadrature_rule* custom_quadrature; - } ufcx_finite_element; - - typedef struct ufcx_basix_custom_finite_element - { - /// Basix identifier of the cell shape - int cell_type; - - /// Dimension of the value space for axis i - int value_shape_length; - - /// Dimension of the value space for axis i - int* value_shape; - - /// The number of rows in the wcoeffs matrix - int wcoeffs_rows; - - /// The number of columns in the wcoeffs matrix - int wcoeffs_cols; - - /// The coefficients that define the polynomial set of the element in terms - /// of the orthonormal polynomials on the cell - double* wcoeffs; - - /// The number of interpolation points associated with each entity - int* npts; - - /// The number of DOFs associated with each entity - int* ndofs; - - // The coordinates of the interpolation points - double* x; - - // The entries in the interpolation matrices - double* M; - - /// The map type for the element - int map_type; - - /// The Sobolev space for the element - int sobolev_space; - - /// Indicates whether or not this is the discontinuous version of the element - bool discontinuous; - - /// The highest degree full polynomial space contained in this element - int embedded_subdegree; - - /// The number of derivatives needed when interpolating - int interpolation_nderivs; - - /// The highest degree of a polynomial in the element - int embedded_superdegree; - - /// The polyset type of the element - int polyset_type; - } ufcx_basix_custom_finite_element; - typedef struct ufcx_quadrature_rule { /// Cell shape @@ -216,41 +84,6 @@ extern "C" double* weights; } ufcx_quadrature_rule; - typedef struct ufcx_dofmap - { - /// String identifying the dofmap - const char* signature; - - /// Number of dofs with global support (i.e. global constants) - int num_global_support_dofs; - - /// Dimension of the local finite element function space for a cell - /// (not including global support dofs) - int num_element_support_dofs; - - /// Return the block size for a VectorElement or TensorElement - int block_size; - - /// Flattened list of dofs associated with each entity - int *entity_dofs; - - /// Offset for dofs of each entity in entity_dofs - int *entity_dof_offsets; - - /// Flattened list of closure dofs associated with each entity - int *entity_closure_dofs; - - /// Offset for closure dofs of each entity in entity_closure_dofs - int *entity_closure_dof_offsets; - - /// Number of sub dofmaps (for a mixed element) - int num_sub_dofmaps; - - /// Get a dofmap for sub dofmap i (for a mixed element) - ufcx_dofmap** sub_dofmaps; - - } ufcx_dofmap; - /// Tabulate integral into tensor A with compiled quadrature rule /// /// @param[out] A @@ -329,7 +162,7 @@ extern "C" bool needs_facet_permutations; /// Get the coordinate element associated with the geometry of the mesh. - ufcx_finite_element* coordinate_element; + long int coordinate_element; } ufcx_integral; typedef struct ufcx_expression @@ -426,20 +259,12 @@ extern "C" /// List of names of constants const char** constant_name_map; - /// Get a finite element for the i-th argument function, where 0 <= + /// Get the hash of the finite element for the i-th argument function, where 0 <= /// i < r + n. /// /// @param i Argument number if 0 <= i < r Coefficient number j = i /// - r if r + j <= i < r + n - ufcx_finite_element** finite_elements; - - /// Get a dofmap for the i-th argument function, where 0 <= i < r + - /// n. - /// - /// @param i - /// Argument number if 0 <= i < r - /// Coefficient number j=i-r if r+j <= i < r+n - ufcx_dofmap** dofmaps; + long int* finite_elements; /// List of cell, interior facet and exterior facet integrals ufcx_integral** form_integrals; @@ -455,8 +280,8 @@ extern "C" // FIXME: Formalise a UFCX 'function space' typedef struct ufcx_function_space { - ufcx_finite_element* finite_element; - ufcx_dofmap* dofmap; + /// Hash of the finite element + long int finite_element; /// The family of the finite element for the geometry map const char* geometry_family; diff --git a/ffcx/ir/analysis/graph.py b/ffcx/ir/analysis/graph.py index 1a73e783f..0f52bf63e 100644 --- a/ffcx/ir/analysis/graph.py +++ b/ffcx/ir/analysis/graph.py @@ -169,7 +169,7 @@ def rebuild_with_scalar_subexpressions(G): if isinstance(vop, ufl.classes.MultiIndex): # TODO: Store MultiIndex in G.V and allocate a symbol to it for this to work if not isinstance(expr, ufl.classes.IndexSum): - raise RuntimeError("Not expecting a %s." % type(expr)) + raise RuntimeError(f"Not expecting a {type(expr)}.") sops.append(()) else: # TODO: Build edge datastructure and use instead? diff --git a/ffcx/ir/analysis/reconstruct.py b/ffcx/ir/analysis/reconstruct.py index 19973fa24..82e2f22ef 100644 --- a/ffcx/ir/analysis/reconstruct.py +++ b/ffcx/ir/analysis/reconstruct.py @@ -182,4 +182,4 @@ def reconstruct(o, *args): if isinstance(o, k): return _reconstruct_call_lookup[k](o, *args) # Nothing found - raise RuntimeError("Not expecting expression of type %s in here." % type(o)) + raise RuntimeError(f"Not expecting expression of type {type(o)} in here.") diff --git a/ffcx/ir/analysis/valuenumbering.py b/ffcx/ir/analysis/valuenumbering.py index 5618cec15..512e6070c 100644 --- a/ffcx/ir/analysis/valuenumbering.py +++ b/ffcx/ir/analysis/valuenumbering.py @@ -84,7 +84,7 @@ def compute_symbols(self): if symbol is None: # Nothing found - raise RuntimeError("Not expecting type %s here." % type(expr)) + raise RuntimeError(f"Not expecting type {type(expr)} here.") self.V_symbols.append(symbol) diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index bc24e04fc..1d2a9ed62 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -6,9 +6,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-later """Compiler stage 2: Code representation. -Module computes intermediate representations of forms, elements and -dofmaps. For each UFC function, we extract the data needed for code -generation at a later stage. +Module computes intermediate representations of forms. For each UFC +function, we extract the data needed for code generation at a later stage. The representation should conform strictly to the naming and order of functions in UFC. Thus, for code generation of the function "foo", one @@ -55,29 +54,11 @@ class FormIR(typing.NamedTuple): original_coefficient_position: list[int] coefficient_names: list[str] constant_names: list[str] - finite_elements: list[str] - dofmaps: list[str] + finite_elements: list[int] integral_names: dict[str, list[str]] subdomain_ids: dict[str, list[int]] -class CustomElementIR(typing.NamedTuple): - """Intermediate representation of a custom element.""" - - cell_type: basix.CellType - value_shape: tuple[int, ...] - wcoeffs: npt.NDArray[np.float64] - x: list[list[npt.NDArray[np.float64]]] - M: list[list[npt.NDArray[np.float64]]] - map_type: basix.MapType - sobolev_space: basix.SobolevSpace - interpolation_nderivs: int - discontinuous: bool - embedded_subdegree: int - embedded_superdegree: int - polyset_type: basix.PolysetType - - class QuadratureIR(typing.NamedTuple): """Intermediate representation of a quadrature rule.""" @@ -86,48 +67,6 @@ class QuadratureIR(typing.NamedTuple): weights: npt.NDArray[np.float64] -class ElementIR(typing.NamedTuple): - """Intermediate representation of an element.""" - - id: int - name: str - signature: str - cell_shape: str - topological_dimension: int - space_dimension: int - reference_value_shape: tuple[int, ...] - degree: int - symmetric: bool - num_sub_elements: int - block_size: int - sub_elements: list[str] - element_type: str - entity_dofs: list[list[list[int]]] - lagrange_variant: basix.LagrangeVariant - dpc_variant: basix.DPCVariant - basix_family: basix.ElementFamily - basix_cell: basix.CellType - discontinuous: bool - custom_element: CustomElementIR - custom_quadrature: QuadratureIR - - -class DofMapIR(typing.NamedTuple): - """Intermediate representation of a DOF map.""" - - id: int - name: str - signature: str - num_global_support_dofs: int - num_element_support_dofs: int - entity_dofs: list[list[list[int]]] - entity_closure_dofs: list[list[list[int]]] - num_entity_closure_dofs: list[list[int]] - num_sub_dofmaps: int - sub_dofmaps: list[str] - block_size: int - - class IntegralIR(typing.NamedTuple): """Intermediate representation of an integral.""" @@ -144,7 +83,7 @@ class IntegralIR(typing.NamedTuple): integrand: dict[QuadratureRule, dict] name: str needs_facet_permutations: bool - coordinate_element: str + coordinate_element: int class ExpressionIR(typing.NamedTuple): @@ -176,8 +115,6 @@ class ExpressionIR(typing.NamedTuple): class DataIR(typing.NamedTuple): """Intermediate representation of data.""" - elements: list[ElementIR] - dofmaps: list[DofMapIR] integrals: list[IntegralIR] forms: list[FormIR] expressions: list[ExpressionIR] @@ -198,10 +135,7 @@ def compute_ir( # Compute object names # NOTE: This is done here for performance reasons, because repeated calls # within each IR computation would be expensive due to UFL signature computations - finite_element_names = { - e: naming.finite_element_name(e, prefix) for e in analysis.unique_elements - } - dofmap_names = {e: naming.dofmap_name(e, prefix) for e in analysis.unique_elements} + finite_element_hashes = {e: hash(e) for e in analysis.unique_elements} integral_names = {} form_names = {} for fd_index, fd in enumerate(analysis.form_data): @@ -211,23 +145,13 @@ def compute_ir( fd.original_form, itg_data.integral_type, fd_index, itg_data.subdomain_id, prefix ) - ir_elements = [ - _compute_element_ir(e, analysis.element_numbers, finite_element_names) - for e in analysis.unique_elements - ] - - ir_dofmaps = [ - _compute_dofmap_ir(e, analysis.element_numbers, dofmap_names) - for e in analysis.unique_elements - ] - irs = [ _compute_integral_ir( fd, i, analysis.element_numbers, integral_names, - finite_element_names, + finite_element_hashes, options, visualise, ) @@ -243,8 +167,7 @@ def compute_ir( form_names, integral_names, analysis.element_numbers, - finite_element_names, - dofmap_names, + finite_element_hashes, object_names, ) for (i, fd) in enumerate(analysis.form_data) @@ -259,133 +182,26 @@ def compute_ir( options, visualise, object_names, - finite_element_names, - dofmap_names, + finite_element_hashes, ) for i, expr in enumerate(analysis.expressions) ] return DataIR( - elements=ir_elements, - dofmaps=ir_dofmaps, integrals=ir_integrals, forms=ir_forms, expressions=ir_expressions, ) -def _compute_element_ir(element, element_numbers, finite_element_names): - """Compute intermediate representation of element.""" - logger.info(f"Computing IR for element {element}") - - # Create basix elements - cell = element.cell - - # Store id - ir = {"id": element_numbers[element]} - ir["name"] = finite_element_names[element] - - # Compute data for each function - ir["signature"] = repr(element) - ir["cell_shape"] = element.cell_type.name - ir["topological_dimension"] = cell.topological_dimension() - ir["space_dimension"] = element.dim + element.num_global_support_dofs - ir["element_type"] = element.ufcx_element_type - ir["lagrange_variant"] = element.lagrange_variant - ir["dpc_variant"] = element.dpc_variant - ir["basix_family"] = element.element_family - ir["basix_cell"] = element.cell_type - ir["discontinuous"] = element.discontinuous - ir["degree"] = element.degree - ir["symmetric"] = isinstance(element, basix.ufl._BlockedElement) and isinstance( - element._pullback, ufl.pullback.SymmetricPullback - ) - ir["reference_value_shape"] = element.reference_value_shape - - ir["num_sub_elements"] = element.num_sub_elements - ir["sub_elements"] = [finite_element_names[e] for e in element.sub_elements] - - ir["block_size"] = element.block_size - if element.block_size > 1: - element = element._sub_element - - ir["entity_dofs"] = element.entity_dofs - - if element.is_custom_element: - ir["custom_element"] = _compute_custom_element_ir(element._element) - else: - ir["custom_element"] = None - - if element.has_custom_quadrature: - ir["custom_quadrature"] = _compute_custom_quadrature_ir(element) - else: - ir["custom_quadrature"] = None - - return ElementIR(**ir) - - -def _compute_custom_element_ir( - basix_element: basix.finite_element.FiniteElement, -) -> CustomElementIR: - """Compute intermediate representation of a custom Basix element.""" - ir: dict[str, typing.Any] = {} - ir["cell_type"] = basix_element.cell_type - ir["value_shape"] = basix_element.value_shape - ir["wcoeffs"] = basix_element.wcoeffs - ir["x"] = basix_element.x - ir["M"] = basix_element.M - ir["map_type"] = basix_element.map_type - ir["sobolev_space"] = basix_element.sobolev_space - ir["discontinuous"] = basix_element.discontinuous - ir["interpolation_nderivs"] = basix_element.interpolation_nderivs - ir["embedded_subdegree"] = basix_element.embedded_subdegree - ir["embedded_superdegree"] = basix_element.embedded_superdegree - ir["polyset_type"] = basix_element.polyset_type - - return CustomElementIR(**ir) - - -def _compute_custom_quadrature_ir(element: basix.ufl._ElementBase) -> QuadratureIR: - """Compute intermediate representation of a custom Basix element.""" - ir: dict[str, typing.Any] = {} - ir["cell_shape"] = element.cell_type.name - ir["points"], ir["weights"] = element.custom_quadrature() - - return QuadratureIR(**ir) - - -def _compute_dofmap_ir(element, element_numbers, dofmap_names): - """Compute intermediate representation of dofmap.""" - logger.info(f"Computing IR for dofmap of {element}") - - # Store id - ir = {"id": element_numbers[element]} - ir["name"] = dofmap_names[element] - - # Compute data for each function - ir["signature"] = "FFCx dofmap for " + repr(element) - ir["sub_dofmaps"] = [dofmap_names[e] for e in element.sub_elements] - ir["num_sub_dofmaps"] = element.num_sub_elements - - ir["block_size"] = element.block_size - if element.block_size > 1: - element = element._sub_element - - ir["entity_dofs"] = element.entity_dofs - ir["entity_closure_dofs"] = element.entity_closure_dofs - - num_dofs_per_entity_closure = [i[0] for i in element.num_entity_closure_dofs] - ir["num_entity_closure_dofs"] = num_dofs_per_entity_closure - ir["entity_closure_dofs"] = element.entity_closure_dofs - - ir["num_global_support_dofs"] = element.num_global_support_dofs - ir["num_element_support_dofs"] = element.dim - - return DofMapIR(**ir) - - def _compute_integral_ir( - form_data, form_index, element_numbers, integral_names, finite_element_names, options, visualise + form_data, + form_index, + element_numbers, + integral_names, + finite_element_hashes, + options, + visualise, ) -> list[IntegralIR]: """Compute intermediate representation for form integrals.""" _entity_types = { @@ -413,7 +229,7 @@ def _compute_integral_ir( "rank": form_data.rank, "entitytype": entitytype, "enabled_coefficients": itg_data.enabled_coefficients, - "coordinate_element": finite_element_names[itg_data.domain.ufl_coordinate_element()], + "coordinate_element": finite_element_hashes[itg_data.domain.ufl_coordinate_element()], } # Get element space dimensions @@ -612,8 +428,7 @@ def _compute_form_ir( form_names, integral_names, element_numbers, - finite_element_names, - dofmap_names, + finite_element_hashes, object_names, ) -> FormIR: """Compute intermediate representation of form.""" @@ -643,14 +458,10 @@ def _compute_form_ir( ir["original_coefficient_position"] = form_data.original_coefficient_positions ir["finite_elements"] = [ - finite_element_names[e] + finite_element_hashes[e] for e in form_data.argument_elements + form_data.coefficient_elements ] - ir["dofmaps"] = [ - dofmap_names[e] for e in form_data.argument_elements + form_data.coefficient_elements - ] - fs = {} for function in form_data.original_form.arguments() + tuple(form_data.reduced_coefficients): name = object_names.get(id(function), str(function)) @@ -667,8 +478,7 @@ def _compute_form_ir( degree = cmap.degree value_shape = space.value_shape fs[name] = ( - finite_element_names[el], - dofmap_names[el], + finite_element_hashes[el], family, degree, cmap.cell_type, @@ -712,8 +522,7 @@ def _compute_expression_ir( options, visualise, object_names, - finite_element_names, - dofmap_names, + finite_element_hashes, ): """Compute intermediate representation of expression.""" logger.info(f"Computing IR for expression {index}") @@ -788,8 +597,7 @@ def _compute_expression_ir( degree = cmap.degree value_shape = space.value_shape fs[name] = ( - finite_element_names[el], - dofmap_names[el], + finite_element_hashes[el], family, degree, cmap.cell_type, diff --git a/ffcx/naming.py b/ffcx/naming.py index df6cc1203..293d0d69c 100644 --- a/ffcx/naming.py +++ b/ffcx/naming.py @@ -9,7 +9,6 @@ import hashlib -import basix.ufl import numpy as np import numpy.typing as npt import ufl @@ -19,9 +18,7 @@ def compute_signature( - ufl_objects: list[ - ufl.Form | basix.ufl._ElementBase | tuple[ufl.core.expr.Expr, npt.NDArray[np.float64]] - ], + ufl_objects: list[ufl.Form | tuple[ufl.core.expr.Expr, npt.NDArray[np.float64]]], tag: str, ) -> str: """Compute the signature hash. @@ -34,9 +31,6 @@ def compute_signature( if isinstance(ufl_object, ufl.Form): kind = "form" object_signature += ufl_object.signature() - elif isinstance(ufl_object, ufl.AbstractFiniteElement): - object_signature += repr(ufl_object) - kind = "element" elif isinstance(ufl_object, tuple) and isinstance(ufl_object[0], ufl.core.expr.Expr): expr = ufl_object[0] points = ufl_object[1] @@ -102,20 +96,6 @@ def form_name(original_form: ufl.form.Form, form_id: int, prefix: str) -> str: return f"form_{sig}" -def finite_element_name(ufl_element: basix.ufl._ElementBase, prefix: str) -> str: - """Get finite element name.""" - assert isinstance(ufl_element, basix.ufl._ElementBase) - sig = compute_signature([ufl_element], prefix) - return f"element_{sig}" - - -def dofmap_name(ufl_element: basix.ufl._ElementBase, prefix: str) -> str: - """Get DOF map name.""" - assert isinstance(ufl_element, basix.ufl._ElementBase) - sig = compute_signature([ufl_element], prefix) - return f"dofmap_{sig}" - - def expression_name( expression: tuple[ufl.core.expr.Expr, npt.NDArray[np.floating]], prefix: str ) -> str: diff --git a/test/test_blocked_elements.py b/test/test_blocked_elements.py deleted file mode 100644 index d72cb4e78..000000000 --- a/test/test_blocked_elements.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (C) 2020 Matthew Scroggs -# -# This file is part of FFCx. (https://www.fenicsproject.org) -# -# SPDX-License-Identifier: LGPL-3.0-or-later - -import basix.ufl -import numpy as np - -import ffcx -import ffcx.codegeneration.jit - - -def test_finite_element(compile_args): - ufl_element = basix.ufl.element("Lagrange", "triangle", 1) - jit_compiled_elements, module, code = ffcx.codegeneration.jit.compile_elements( - [ufl_element], cffi_extra_compile_args=compile_args - ) - ufcx_element, ufcx_dofmap = jit_compiled_elements[0] - - assert ufcx_element.topological_dimension == 2 - assert ufcx_element.space_dimension == 3 - assert ufcx_element.reference_value_rank == 0 - assert ufcx_element.reference_value_size == 1 - assert ufcx_element.block_size == 1 - assert ufcx_element.num_sub_elements == 0 - - assert ufcx_dofmap.block_size == 1 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_element_support_dofs == 3 - off = np.array([ufcx_dofmap.entity_dof_offsets[i] for i in range(8)]) - assert np.all(np.diff(off) == [1, 1, 1, 0, 0, 0, 0]) - - for v in range(3): - assert ufcx_dofmap.entity_dofs[v] == v - assert ufcx_dofmap.num_sub_dofmaps == 0 - - -def test_vector_element(compile_args): - ufl_element = basix.ufl.element("Lagrange", "triangle", 1, shape=(2,)) - jit_compiled_elements, module, code = ffcx.codegeneration.jit.compile_elements( - [ufl_element], cffi_extra_compile_args=compile_args - ) - ufcx_element, ufcx_dofmap = jit_compiled_elements[0] - - assert ufcx_element.topological_dimension == 2 - assert ufcx_element.space_dimension == 6 - assert ufcx_element.reference_value_rank == 1 - assert ufcx_element.reference_value_shape[0] == 2 - assert ufcx_element.reference_value_size == 2 - assert ufcx_element.block_size == 2 - assert ufcx_element.num_sub_elements == 2 - - assert ufcx_dofmap.block_size == 2 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_element_support_dofs == 3 - off = np.array([ufcx_dofmap.entity_dof_offsets[i] for i in range(8)]) - assert np.all(np.diff(off) == [1, 1, 1, 0, 0, 0, 0]) - - for v in range(3): - assert ufcx_dofmap.entity_dofs[v] == v - assert ufcx_dofmap.num_sub_dofmaps == 2 - - -def test_tensor_element(compile_args): - ufl_element = basix.ufl.element("Lagrange", "triangle", 1, shape=(2, 2)) - jit_compiled_elements, module, code = ffcx.codegeneration.jit.compile_elements( - [ufl_element], cffi_extra_compile_args=compile_args - ) - ufcx_element, ufcx_dofmap = jit_compiled_elements[0] - - assert ufcx_element.topological_dimension == 2 - assert ufcx_element.space_dimension == 12 - assert ufcx_element.reference_value_rank == 2 - assert ufcx_element.reference_value_shape[0] == 2 - assert ufcx_element.reference_value_shape[1] == 2 - assert ufcx_element.reference_value_size == 4 - assert ufcx_element.block_size == 4 - assert ufcx_element.num_sub_elements == 4 - - assert ufcx_dofmap.block_size == 4 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_element_support_dofs == 3 - off = np.array([ufcx_dofmap.entity_dof_offsets[i] for i in range(8)]) - assert np.all(np.diff(off) == [1, 1, 1, 0, 0, 0, 0]) - - for v in range(3): - assert ufcx_dofmap.entity_dofs[v] == v - assert ufcx_dofmap.num_sub_dofmaps == 4 - - -def test_vector_quadrature_element(compile_args): - ufl_element = basix.ufl.blocked_element( - basix.ufl.quadrature_element("tetrahedron", degree=2, scheme="default"), shape=(3,) - ) - jit_compiled_elements, module, code = ffcx.codegeneration.jit.compile_elements( - [ufl_element], cffi_extra_compile_args=compile_args - ) - ufcx_element, ufcx_dofmap = jit_compiled_elements[0] - - assert ufcx_element.topological_dimension == 3 - assert ufcx_element.space_dimension == 12 - assert ufcx_element.reference_value_rank == 1 - assert ufcx_element.reference_value_shape[0] == 3 - assert ufcx_element.reference_value_size == 3 - assert ufcx_element.block_size == 3 - assert ufcx_element.num_sub_elements == 3 - - assert ufcx_dofmap.block_size == 3 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_global_support_dofs == 0 - assert ufcx_dofmap.num_element_support_dofs == 4 - off = np.array([ufcx_dofmap.entity_dof_offsets[i] for i in range(16)]) - assert np.all(np.diff(off) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]) - - for i in range(4): - assert ufcx_dofmap.entity_dofs[i] == i - - assert ufcx_dofmap.num_sub_dofmaps == 3