From 40575eafc2f3d8736de3d7c433e269c5f6bee1ea Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Wed, 17 Jan 2024 17:23:40 +0000 Subject: [PATCH 01/16] remove information about physical elements from ffc element --- ffcx/codegeneration/C/finite_element.py | 14 +------------- ffcx/codegeneration/C/finite_element_template.py | 5 ----- ffcx/codegeneration/ufcx.h | 12 ------------ ffcx/ir/representation.py | 2 -- test/test_blocked_elements.py | 16 ---------------- test/test_elements.py | 2 +- 6 files changed, 2 insertions(+), 49 deletions(-) diff --git a/ffcx/codegeneration/C/finite_element.py b/ffcx/codegeneration/C/finite_element.py index 0f530c16e..79e3524ac 100644 --- a/ffcx/codegeneration/C/finite_element.py +++ b/ffcx/codegeneration/C/finite_element.py @@ -23,19 +23,16 @@ 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.value_shape}") + 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["geometric_dimension"] = ir.geometric_dimension 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["value_rank"] = len(ir.value_shape) - d["value_size"] = ufl.product(ir.value_shape) d["reference_value_rank"] = len(ir.reference_value_shape) d["reference_value_size"] = ufl.product(ir.reference_value_shape) d["degree"] = ir.degree @@ -62,15 +59,6 @@ def generator(ir, options): else: d["basix_cell"] = int(ir.basix_cell) - if len(ir.value_shape) > 0: - d["value_shape"] = f"value_shape_{ir.name}" - values = ", ".join(str(i) for i in ir.value_shape) - sizes = len(ir.value_shape) - d["value_shape_init"] = f"int value_shape_{ir.name}[{sizes}] = {{{values}}};" - else: - d["value_shape"] = "NULL" - d["value_shape_init"] = "" - 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) diff --git a/ffcx/codegeneration/C/finite_element_template.py b/ffcx/codegeneration/C/finite_element_template.py index 13503fccf..fab38174f 100644 --- a/ffcx/codegeneration/C/finite_element_template.py +++ b/ffcx/codegeneration/C/finite_element_template.py @@ -10,7 +10,6 @@ factory = """ // Code for element {factory_name} -{value_shape_init} {reference_value_shape_init} {sub_elements_init} {custom_element_init} @@ -22,11 +21,7 @@ .cell_shape = {cell_shape}, .element_type = {element_type}, .topological_dimension = {topological_dimension}, - .geometric_dimension = {geometric_dimension}, .space_dimension = {space_dimension}, - .value_rank = {value_rank}, - .value_shape = {value_shape}, - .value_size = {value_size}, .reference_value_rank = {reference_value_rank}, .reference_value_shape = {reference_value_shape}, .reference_value_size = {reference_value_size}, diff --git a/ffcx/codegeneration/ufcx.h b/ffcx/codegeneration/ufcx.h index c8ac20b61..22e37f1f1 100644 --- a/ffcx/codegeneration/ufcx.h +++ b/ffcx/codegeneration/ufcx.h @@ -92,21 +92,9 @@ extern "C" /// Topological dimension of the cell int topological_dimension; - /// Geometric dimension of the cell - int geometric_dimension; - /// Dimension of the finite element function space int space_dimension; - /// Rank of the value space - int value_rank; - - /// Dimension of the value space for axis i - int* value_shape; - - /// Number of components of the value space - int value_size; - /// Rank of the reference value space int reference_value_rank; diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index 0a9f8617b..48dc351bb 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -83,7 +83,6 @@ class ElementIR(typing.NamedTuple): signature: str cell_shape: str topological_dimension: int - geometric_dimension: int space_dimension: int value_shape: typing.Tuple[int, ...] reference_value_shape: typing.Tuple[int, ...] @@ -233,7 +232,6 @@ def _compute_element_ir(element, element_numbers, finite_element_names): ir["signature"] = repr(element) ir["cell_shape"] = element.cell_type.name ir["topological_dimension"] = cell.topological_dimension() - ir["geometric_dimension"] = cell.geometric_dimension() ir["space_dimension"] = element.dim + element.num_global_support_dofs ir["element_type"] = element.ufcx_element_type ir["lagrange_variant"] = element.lagrange_variant diff --git a/test/test_blocked_elements.py b/test/test_blocked_elements.py index 9ca977f96..04d2e64bd 100644 --- a/test/test_blocked_elements.py +++ b/test/test_blocked_elements.py @@ -18,10 +18,7 @@ def test_finite_element(compile_args): ufcx_element, ufcx_dofmap = jit_compiled_elements[0] assert ufcx_element.topological_dimension == 2 - assert ufcx_element.geometric_dimension == 2 assert ufcx_element.space_dimension == 3 - assert ufcx_element.value_rank == 0 - assert ufcx_element.value_size == 1 assert ufcx_element.reference_value_rank == 0 assert ufcx_element.reference_value_size == 1 assert ufcx_element.block_size == 1 @@ -46,11 +43,7 @@ def test_vector_element(compile_args): ufcx_element, ufcx_dofmap = jit_compiled_elements[0] assert ufcx_element.topological_dimension == 2 - assert ufcx_element.geometric_dimension == 2 assert ufcx_element.space_dimension == 6 - assert ufcx_element.value_rank == 1 - assert ufcx_element.value_shape[0] == 2 - assert ufcx_element.value_size == 2 assert ufcx_element.reference_value_rank == 1 assert ufcx_element.reference_value_shape[0] == 2 assert ufcx_element.reference_value_size == 2 @@ -76,12 +69,7 @@ def test_tensor_element(compile_args): ufcx_element, ufcx_dofmap = jit_compiled_elements[0] assert ufcx_element.topological_dimension == 2 - assert ufcx_element.geometric_dimension == 2 assert ufcx_element.space_dimension == 12 - assert ufcx_element.value_rank == 2 - assert ufcx_element.value_shape[0] == 2 - assert ufcx_element.value_shape[1] == 2 - assert ufcx_element.value_size == 4 assert ufcx_element.reference_value_rank == 2 assert ufcx_element.reference_value_shape[0] == 2 assert ufcx_element.reference_value_shape[1] == 2 @@ -109,11 +97,7 @@ def test_vector_quadrature_element(compile_args): ufcx_element, ufcx_dofmap = jit_compiled_elements[0] assert ufcx_element.topological_dimension == 3 - assert ufcx_element.geometric_dimension == 3 assert ufcx_element.space_dimension == 12 - assert ufcx_element.value_rank == 1 - assert ufcx_element.value_shape[0] == 3 - assert ufcx_element.value_size == 3 assert ufcx_element.reference_value_rank == 1 assert ufcx_element.reference_value_shape[0] == 3 assert ufcx_element.reference_value_size == 3 diff --git a/test/test_elements.py b/test/test_elements.py index 22b75aca1..899752eca 100644 --- a/test/test_elements.py +++ b/test/test_elements.py @@ -187,7 +187,7 @@ def test_values(self, family, cell, degree, reference): for x in points: table = e.tabulate(0, np.array([x], dtype=np.float64)) basis = table[0] - if sum(e.value_shape) == 1: + if sum(e.reference_value_shape) == 1: for i, value in enumerate(basis[0]): assert np.isclose(value, reference[i](x)) else: From 7e8ed78a354d3ae475e8130dc7066ba710468906 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Wed, 17 Jan 2024 17:24:38 +0000 Subject: [PATCH 02/16] branches --- .github/workflows/dolfinx-tests.yml | 4 ++-- .github/workflows/pythonapp.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dolfinx-tests.yml b/.github/workflows/dolfinx-tests.yml index 8cb2d9006..08351eb0c 100644 --- a/.github/workflows/dolfinx-tests.yml +++ b/.github/workflows/dolfinx-tests.yml @@ -35,8 +35,8 @@ jobs: - name: Install UFL and Basix (default branches/tags) if: github.event_name != 'workflow_dispatch' run: | - python3 -m pip install git+https://github.com/FEniCS/ufl.git - python3 -m pip install git+https://github.com/FEniCS/basix.git + python3 -m pip install git+https://github.com/FEniCS/ufl.git@mscroggs/gdim + python3 -m pip install git+https://github.com/FEniCS/basix.git@mscroggs/remove-gdim - name: Install UFL and Basix (specified branches/tags) if: github.event_name == 'workflow_dispatch' run: | diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index e2c46b3bd..63c8891cd 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -38,8 +38,8 @@ jobs: run: brew install graphviz ninja pkg-config - name: Install FEniCS dependencies (Python) run: | - pip install git+https://github.com/FEniCS/ufl.git - pip install git+https://github.com/FEniCS/basix.git + pip install git+https://github.com/FEniCS/ufl.git@mscroggs/gdim + pip install git+https://github.com/FEniCS/basix.git@mscroggs/remove-gdim - name: Install FFCx run: pip install .[ci] - name: Lint with flake8 From 90fbe79a889f13b84cdb7032ad4ff1de11c93e7f Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Wed, 17 Jan 2024 17:27:18 +0000 Subject: [PATCH 03/16] update more tests --- test/test_jit_forms.py | 4 ++-- test/test_tensor_product.py | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/test_jit_forms.py b/test/test_jit_forms.py index fb4ba2e81..abc636722 100644 --- a/test/test_jit_forms.py +++ b/test/test_jit_forms.py @@ -811,13 +811,13 @@ def test_facet_vertex_quadrature(compile_args): def test_manifold_derivatives(compile_args): """Test higher order derivatives on manifolds""" - c_el = basix.ufl.element("Lagrange", "interval", 1, shape=(2,), gdim=2) + c_el = basix.ufl.element("Lagrange", "interval", 1, shape=(2,)) mesh = ufl.Mesh(c_el) x = ufl.SpatialCoordinate(mesh) dx = ufl.Measure("dx", domain=mesh) order = 4 - el = basix.ufl.element("Lagrange", "interval", order, gdim=2) + el = basix.ufl.element("Lagrange", "interval", order) V = ufl.FunctionSpace(mesh, el) u = ufl.Coefficient(V) diff --git a/test/test_tensor_product.py b/test/test_tensor_product.py index c0c9c88ee..047e1f5f9 100644 --- a/test/test_tensor_product.py +++ b/test/test_tensor_product.py @@ -25,7 +25,6 @@ def cell_to_gdim(cell_type): def create_tensor_product_element(cell_type, degree, variant, shape=None): """Create tensor product element.""" - gdim = cell_to_gdim(cell_type) family = basix.ElementFamily.P ref = basix.create_element(family, cell_type, degree, variant) factors = ref.get_tensor_product_representation()[0] @@ -33,11 +32,11 @@ def create_tensor_product_element(cell_type, degree, variant, shape=None): dof_ordering = np.argsort(perm) element = basix.create_element(family, cell_type, degree, variant, dof_ordering=dof_ordering) - uflelement = basix.ufl._BasixElement(element, gdim=gdim) + uflelement = basix.ufl._BasixElement(element) if shape is None: return uflelement else: - return basix.ufl.blocked_element(uflelement, shape=shape, gdim=gdim) + return basix.ufl.blocked_element(uflelement, shape=shape) def generate_kernel(forms, dtype, options): From 96fcdaae0346bb661360fbe35510affc1b814645 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Thu, 18 Jan 2024 09:15:15 +0000 Subject: [PATCH 04/16] update demos --- demo/HyperElasticity.py | 2 +- demo/ProjectionManifold.py | 6 +++--- ffcx/codegeneration/access.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demo/HyperElasticity.py b/demo/HyperElasticity.py index bb0b98d21..c20efe6c5 100644 --- a/demo/HyperElasticity.py +++ b/demo/HyperElasticity.py @@ -12,7 +12,7 @@ # Cell and its properties cell = tetrahedron -d = cell.geometric_dimension() +d = 3 # Elements u_element = basix.ufl.element("P", cell.cellname(), 2, shape=(3, )) diff --git a/demo/ProjectionManifold.py b/demo/ProjectionManifold.py index 648aa3107..86613fb91 100644 --- a/demo/ProjectionManifold.py +++ b/demo/ProjectionManifold.py @@ -22,10 +22,10 @@ inner) # Define element over this domain -V = basix.ufl.element("RT", "triangle", 1, gdim=3) -Q = basix.ufl.element("DG", "triangle", 0, gdim=3) +V = basix.ufl.element("RT", "triangle", 1) +Q = basix.ufl.element("DG", "triangle", 0) element = basix.ufl.mixed_element([V, Q]) -domain = Mesh(basix.ufl.element("Lagrange", "triangle", 1, shape=(3, ), gdim=3)) +domain = Mesh(basix.ufl.element("Lagrange", "triangle", 1, shape=(3, ))) space = FunctionSpace(domain, element) (u, p) = TrialFunctions(space) diff --git a/ffcx/codegeneration/access.py b/ffcx/codegeneration/access.py index 75aa51386..f46d3e63f 100644 --- a/ffcx/codegeneration/access.py +++ b/ffcx/codegeneration/access.py @@ -249,7 +249,7 @@ def cell_vertices(self, e, mt, tabledata, num_points): # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, basix.ufl._BlockedElement) - assert coordinate_element.value_shape == (gdim, ) + assert coordinate_element.reference_value_shape == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements) scalar_element = ufl_scalar_element assert scalar_element.value_size == 1 and scalar_element.block_size == 1 From e391f35e60480c9e1b74e435aa2871ad57d2e408 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Thu, 18 Jan 2024 09:15:50 +0000 Subject: [PATCH 05/16] reference value shapes --- ffcx/codegeneration/access.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ffcx/codegeneration/access.py b/ffcx/codegeneration/access.py index f46d3e63f..eaaf787c6 100644 --- a/ffcx/codegeneration/access.py +++ b/ffcx/codegeneration/access.py @@ -252,7 +252,7 @@ def cell_vertices(self, e, mt, tabledata, num_points): assert coordinate_element.reference_value_shape == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements) scalar_element = ufl_scalar_element - assert scalar_element.value_size == 1 and scalar_element.block_size == 1 + assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1 vertex_scalar_dofs = scalar_element.entity_dofs[0] num_scalar_dofs = scalar_element.dim @@ -280,10 +280,10 @@ def cell_edge_vectors(self, e, mt, tabledata, num_points): # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, basix.ufl._BlockedElement) - assert coordinate_element.value_shape == (gdim, ) + assert coordinate_element.reference_value_shape == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements) scalar_element = ufl_scalar_element - assert scalar_element.value_size == 1 and scalar_element.block_size == 1 + assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1 vertex_scalar_dofs = scalar_element.entity_dofs[0] num_scalar_dofs = scalar_element.dim @@ -321,10 +321,10 @@ def facet_edge_vectors(self, e, mt, tabledata, num_points): # Get dimension and dofmap of scalar element assert isinstance(coordinate_element, basix.ufl._BlockedElement) - assert coordinate_element.value_shape == (gdim, ) + assert coordinate_element.reference_value_shape == (gdim, ) ufl_scalar_element, = set(coordinate_element.sub_elements) scalar_element = ufl_scalar_element - assert scalar_element.value_size == 1 and scalar_element.block_size == 1 + assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1 scalar_element = ufl_scalar_element num_scalar_dofs = scalar_element.dim From aeb88c6f03d077c863ce03ee9570c9983ed9653e Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Thu, 18 Jan 2024 10:09:36 +0000 Subject: [PATCH 06/16] dolfinx branch --- .github/workflows/dolfinx-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dolfinx-tests.yml b/.github/workflows/dolfinx-tests.yml index 08351eb0c..7350f7c2f 100644 --- a/.github/workflows/dolfinx-tests.yml +++ b/.github/workflows/dolfinx-tests.yml @@ -51,7 +51,7 @@ jobs: with: path: ./dolfinx repository: FEniCS/dolfinx - ref: main + ref: mscroggs/gdim - name: Get DOLFINx source (specified branch/tag) if: github.event_name == 'workflow_dispatch' uses: actions/checkout@v4 From ab5217b17af9739f44af0a884181732657a1eaa0 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Thu, 18 Jan 2024 17:32:43 +0000 Subject: [PATCH 07/16] Add value shape to function spaces --- ffcx/codegeneration/C/expressions.py | 15 +++++++++++++-- ffcx/codegeneration/C/form.py | 16 +++++++++++++++- ffcx/codegeneration/C/form_template.py | 2 ++ ffcx/codegeneration/ufcx.h | 9 +++++++++ ffcx/ir/representation.py | 14 ++++++++------ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index cd795375c..084cdc706 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -98,13 +98,24 @@ def generator(ir, options): # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) - for (name, (element, dofmap, cmap_family, cmap_degree)) in ir.function_spaces.items(): + for (name, (element, dofmap, cmap_family, cmap_degree, cmap_variant, value_shape)) in ir.function_spaces.items(): + if len(value_shape) > 0: + values = ", ".join(f"{i}" for i in value_shape) + code += [f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{{values}}};"] 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".geometry_family = \"{cmap_family}\","] - code += [f".geometry_degree = {cmap_degree}"] + code += [f".geometry_degree = {cmap_degree},"] + code += [f".geometry_basix_cell = {int(cmap_celltype)},"] + code += [f".geometry_basix_variant = {int(cmap_variant)},"] + code += [f".value_rank = {len(value_shape)},"] + code += [f".value_size = {product(value_shape)},"] + if len(value_shape) == 0: + code += [".value_shape = NULL"] + else: + code += [f".value_shape = value_shape_{name}_{ir.name_from_uflfile}"] code += ["};"] d["function_spaces_alloc"] = "\n".join(code) diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index fb5705434..b48459304 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -14,6 +14,7 @@ import numpy from ffcx.codegeneration.C import form_template +from ufl import product logger = logging.getLogger("ffcx") @@ -116,6 +117,7 @@ def generator(ir, options): d["form_integral_offsets_init"] = f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};" code = [] + vs_code = [] # FIXME: Should be handled differently, revise how # ufcx_function_space is generated @@ -126,7 +128,12 @@ def generator(ir, options): cmap_degree, cmap_celltype, cmap_variant, + value_shape ) in ir.function_spaces.items(): + print(value_shape) + if len(value_shape) > 0: + values = ", ".join(f"{i}" for i in value_shape) + vs_code += [f"int value_shape_{name}[{len(value_shape)}] = {{{values}}};"] code += [f"static ufcx_function_space functionspace_{name} ="] code += ["{"] code += [f".finite_element = &{element},"] @@ -134,7 +141,13 @@ def generator(ir, options): code += [f'.geometry_family = "{cmap_family}",'] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] - code += [f".geometry_basix_variant = {int(cmap_variant)}"] + code += [f".geometry_basix_variant = {int(cmap_variant)},"] + code += [f".value_rank = {len(value_shape)},"] + code += [f".value_size = {product(value_shape)},"] + if len(value_shape) == 0: + code += [".value_shape = NULL"] + else: + code += [f".value_shape = value_shape_{name}"] code += ["};"] for name in ir.function_spaces.keys(): @@ -142,6 +155,7 @@ def generator(ir, options): code += ["return NULL;\n"] + d["functionspace_vs"] = "\n".join(vs_code) d["functionspace"] = "\n".join(code) # Check that no keys are redundant or have been missed diff --git a/ffcx/codegeneration/C/form_template.py b/ffcx/codegeneration/C/form_template.py index df0a5b61c..1f941c78b 100644 --- a/ffcx/codegeneration/C/form_template.py +++ b/ffcx/codegeneration/C/form_template.py @@ -54,6 +54,8 @@ // Alias name ufcx_form* {name_from_uflfile} = &{factory_name}; +{functionspace_vs} + ufcx_function_space* functionspace_{name_from_uflfile}(const char* function_name) {{ {functionspace} diff --git a/ffcx/codegeneration/ufcx.h b/ffcx/codegeneration/ufcx.h index 22e37f1f1..f83edaaa7 100644 --- a/ffcx/codegeneration/ufcx.h +++ b/ffcx/codegeneration/ufcx.h @@ -479,6 +479,15 @@ extern "C" /// The Basix variant of the finite element for the geometry map int geometry_basix_variant; + + /// Rank of the value space + int value_rank; + + /// Dimension of the value space for axis i + int* value_shape; + + /// Number of components of the value space + int value_size; } ufcx_function_space; #ifdef __cplusplus diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index 48dc351bb..e5afabe13 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -46,7 +46,7 @@ class FormIR(typing.NamedTuple): num_coefficients: int num_constants: int name_from_uflfile: str - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int, ...]]] original_coefficient_position: typing.List[int] coefficient_names: typing.List[str] constant_names: typing.List[str] @@ -161,7 +161,7 @@ class ExpressionIR(typing.NamedTuple): coefficient_names: typing.List[str] constant_names: typing.List[str] needs_facet_permutations: bool - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int, ...]]] name_from_uflfile: str original_coefficient_positions: typing.List[int] @@ -559,14 +559,15 @@ def _compute_form_ir(form_data, form_id, prefix, form_names, integral_names, ele if not str(name).isidentifier(): raise ValueError(f"Function name \"{name}\" must be a valid object identifier.") el = function.ufl_function_space().ufl_element() - cmap = function.ufl_function_space().ufl_domain().ufl_coordinate_element() + domain = function.ufl_function_space().ufl_domain() + cmap = domain.ufl_coordinate_element() # Default point spacing for CoordinateElement is equispaced if not isinstance(cmap, basix.ufl._ElementBase) and cmap.variant() is None: cmap._sub_element._variant = "equispaced" family = cmap.family_name degree = cmap.degree fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, - cmap.cell_type, cmap.lagrange_variant) + cmap.cell_type, cmap.lagrange_variant, el.value_shape(domain)) form_name = object_names.get(id(form_data.original_form), form_id) @@ -659,10 +660,11 @@ def _compute_expression_ir(expression, index, prefix, analysis, options, visuali if not str(name).isidentifier(): raise ValueError(f"Function name \"{name}\" must be a valid object identifier.") el = function.ufl_function_space().ufl_element() - cmap = function.ufl_function_space().ufl_domain().ufl_coordinate_element() + domain = function.ufl_function_space().ufl_domain() + cmap = domain.ufl_coordinate_element() family = cmap.family_name degree = cmap.degree - fs[name] = (finite_element_names[el], dofmap_names[el], family, degree) + fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, el.value_shape(domain)) expression_name = object_names.get(id(original_expression), index) From fe2913d2c0799a38218d1bbd1a81d5eb945af2d5 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Mon, 22 Jan 2024 09:42:14 +0000 Subject: [PATCH 08/16] adding value_shape[dim] to finite element --- ffcx/codegeneration/C/finite_element.py | 12 ++++++++++++ .../C/finite_element_template.py | 5 +++++ ffcx/codegeneration/C/form.py | 15 ++------------- ffcx/codegeneration/ufcx.h | 18 +++++++++--------- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/ffcx/codegeneration/C/finite_element.py b/ffcx/codegeneration/C/finite_element.py index 79e3524ac..59f1dee86 100644 --- a/ffcx/codegeneration/C/finite_element.py +++ b/ffcx/codegeneration/C/finite_element.py @@ -68,6 +68,18 @@ def generator(ir, options): d["reference_value_shape"] = "NULL" d["reference_value_shape_init"] = "" + d["value_rank"] = len(ir.value_shape[0]) + d["value_size"] = f"value_size_{ir.name}" + d["value_size_init"] = f"value_size_{ir.name} = {{" + ", ".join([f"{ufl.product(i)}" for i in ir.value_shape]) + "}" + if len(ir.value_shape[0]) > 0: + d["value_shape"] = f"value_shape_{ir.name}" + d["value_shape_init"] = f"int value_shape_{ir.name}[{len(ir.value_shape)}][{len(ir.value_shape[0])}] = {{" + d["value_shape_init"] += ", ".join(["{" + ", ".join([f"{j}" for j in i]) "}" for i in ir.value_shape]) + d["value_shape_init"] += "};" + else: + d["value_shape"] = "NULL" + d["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) diff --git a/ffcx/codegeneration/C/finite_element_template.py b/ffcx/codegeneration/C/finite_element_template.py index fab38174f..06a835331 100644 --- a/ffcx/codegeneration/C/finite_element_template.py +++ b/ffcx/codegeneration/C/finite_element_template.py @@ -10,6 +10,8 @@ factory = """ // Code for element {factory_name} +{value_shape_init} +{value_size_init} {reference_value_shape_init} {sub_elements_init} {custom_element_init} @@ -25,6 +27,9 @@ .reference_value_rank = {reference_value_rank}, .reference_value_shape = {reference_value_shape}, .reference_value_size = {reference_value_size}, + .value_rank = {value_rank}, + .value_shape = {value_shape}, + .value_size = {value_size}, .degree = {degree}, .block_size = {block_size}, .basix_family = {basix_family}, diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index b48459304..2a54ea04e 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -127,13 +127,8 @@ def generator(ir, options): cmap_family, cmap_degree, cmap_celltype, - cmap_variant, - value_shape + cmap_variant ) in ir.function_spaces.items(): - print(value_shape) - if len(value_shape) > 0: - values = ", ".join(f"{i}" for i in value_shape) - vs_code += [f"int value_shape_{name}[{len(value_shape)}] = {{{values}}};"] code += [f"static ufcx_function_space functionspace_{name} ="] code += ["{"] code += [f".finite_element = &{element},"] @@ -141,13 +136,7 @@ def generator(ir, options): code += [f'.geometry_family = "{cmap_family}",'] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] - code += [f".geometry_basix_variant = {int(cmap_variant)},"] - code += [f".value_rank = {len(value_shape)},"] - code += [f".value_size = {product(value_shape)},"] - if len(value_shape) == 0: - code += [".value_shape = NULL"] - else: - code += [f".value_shape = value_shape_{name}"] + code += [f".geometry_basix_variant = {int(cmap_variant)}"] code += ["};"] for name in ir.function_spaces.keys(): diff --git a/ffcx/codegeneration/ufcx.h b/ffcx/codegeneration/ufcx.h index f83edaaa7..d8ec54722 100644 --- a/ffcx/codegeneration/ufcx.h +++ b/ffcx/codegeneration/ufcx.h @@ -104,6 +104,15 @@ extern "C" /// Number of components of the reference value space int reference_value_size; + /// Rank of the value space + int value_rank; + + /// Shape of the value space for gdim 0 to 3 + int** value_shape; + + /// Dimension of the value space for gdim 0 to 3 + int* value_size; + /// Maximum polynomial degree of the finite element function space int degree; @@ -479,15 +488,6 @@ extern "C" /// The Basix variant of the finite element for the geometry map int geometry_basix_variant; - - /// Rank of the value space - int value_rank; - - /// Dimension of the value space for axis i - int* value_shape; - - /// Number of components of the value space - int value_size; } ufcx_function_space; #ifdef __cplusplus From 1db169a61e15a3b994eb00c3b5fec9fcd41ca93d Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Mon, 22 Jan 2024 10:55:37 +0000 Subject: [PATCH 09/16] write value_shape for each gdim into generated code --- ffcx/codegeneration/C/expressions.py | 13 ++----------- ffcx/codegeneration/C/finite_element.py | 22 +++++++++++++--------- ffcx/codegeneration/C/form.py | 3 --- ffcx/codegeneration/C/form_template.py | 2 -- ffcx/ir/representation.py | 13 +++++++------ 5 files changed, 22 insertions(+), 31 deletions(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index 084cdc706..a7c514e92 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -98,10 +98,7 @@ def generator(ir, options): # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) - for (name, (element, dofmap, cmap_family, cmap_degree, cmap_variant, value_shape)) in ir.function_spaces.items(): - if len(value_shape) > 0: - values = ", ".join(f"{i}" for i in value_shape) - code += [f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{{values}}};"] + for (name, (element, dofmap, cmap_family, cmap_degree, cmap_celltype, cmap_variant)) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] code += [f".finite_element = &{element},"] @@ -109,13 +106,7 @@ def generator(ir, options): code += [f".geometry_family = \"{cmap_family}\","] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] - code += [f".geometry_basix_variant = {int(cmap_variant)},"] - code += [f".value_rank = {len(value_shape)},"] - code += [f".value_size = {product(value_shape)},"] - if len(value_shape) == 0: - code += [".value_shape = NULL"] - else: - code += [f".value_shape = value_shape_{name}_{ir.name_from_uflfile}"] + code += [f".geometry_basix_variant = {int(cmap_variant)}"] code += ["};"] d["function_spaces_alloc"] = "\n".join(code) diff --git a/ffcx/codegeneration/C/finite_element.py b/ffcx/codegeneration/C/finite_element.py index 59f1dee86..2725e067e 100644 --- a/ffcx/codegeneration/C/finite_element.py +++ b/ffcx/codegeneration/C/finite_element.py @@ -68,17 +68,21 @@ def generator(ir, options): d["reference_value_shape"] = "NULL" d["reference_value_shape_init"] = "" - d["value_rank"] = len(ir.value_shape[0]) + rank = len(ir.value_shape[0]) + d["value_rank"] = rank d["value_size"] = f"value_size_{ir.name}" - d["value_size_init"] = f"value_size_{ir.name} = {{" + ", ".join([f"{ufl.product(i)}" for i in ir.value_shape]) + "}" - if len(ir.value_shape[0]) > 0: - d["value_shape"] = f"value_shape_{ir.name}" - d["value_shape_init"] = f"int value_shape_{ir.name}[{len(ir.value_shape)}][{len(ir.value_shape[0])}] = {{" - d["value_shape_init"] += ", ".join(["{" + ", ".join([f"{j}" for j in i]) "}" for i in ir.value_shape]) - d["value_shape_init"] += "};" + d["value_size_init"] = f"int value_size_{ir.name}[4] = {{" + ", ".join([ + f"{ufl.product(i)}" for i in ir.value_shape]) + "};" + d["value_shape"] = f"value_shape_{ir.name}" + d["value_shape_init"] = "" + if rank > 0: + for i in range(4): + d["value_shape_init"] += f"int value_shape_{ir.name}_{i}[{rank}] = {{" + ", ".join([ + f"{j}" for j in ir.value_shape[i]]) + "};\n" + d["value_shape_init"] += f"int* value_shape_{ir.name}[4] = {{" + ", ".join([ + f"value_shape_{ir.name}_{i}" for i in range(4)]) + "};" else: - d["value_shape"] = "NULL" - d["value_shape_init"] = "" + d["value_shape_init"] += f"int* value_shape_{ir.name}[4] = {{" + ", ".join(["NULL" for i in range(4)]) + "};" if len(ir.sub_elements) > 0: d["sub_elements"] = f"sub_elements_{ir.name}" diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index 2a54ea04e..d4c854168 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -14,7 +14,6 @@ import numpy from ffcx.codegeneration.C import form_template -from ufl import product logger = logging.getLogger("ffcx") @@ -117,7 +116,6 @@ def generator(ir, options): d["form_integral_offsets_init"] = f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};" code = [] - vs_code = [] # FIXME: Should be handled differently, revise how # ufcx_function_space is generated @@ -144,7 +142,6 @@ def generator(ir, options): code += ["return NULL;\n"] - d["functionspace_vs"] = "\n".join(vs_code) d["functionspace"] = "\n".join(code) # Check that no keys are redundant or have been missed diff --git a/ffcx/codegeneration/C/form_template.py b/ffcx/codegeneration/C/form_template.py index 1f941c78b..df0a5b61c 100644 --- a/ffcx/codegeneration/C/form_template.py +++ b/ffcx/codegeneration/C/form_template.py @@ -54,8 +54,6 @@ // Alias name ufcx_form* {name_from_uflfile} = &{factory_name}; -{functionspace_vs} - ufcx_function_space* functionspace_{name_from_uflfile}(const char* function_name) {{ {functionspace} diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index e5afabe13..a3095360d 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -46,7 +46,7 @@ class FormIR(typing.NamedTuple): num_coefficients: int num_constants: int name_from_uflfile: str - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int, ...]]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] original_coefficient_position: typing.List[int] coefficient_names: typing.List[str] constant_names: typing.List[str] @@ -84,7 +84,7 @@ class ElementIR(typing.NamedTuple): cell_shape: str topological_dimension: int space_dimension: int - value_shape: typing.Tuple[int, ...] + value_shape: typing.List[typing.Tuple[int, ...]] reference_value_shape: typing.Tuple[int, ...] degree: int num_sub_elements: int @@ -161,7 +161,7 @@ class ExpressionIR(typing.NamedTuple): coefficient_names: typing.List[str] constant_names: typing.List[str] needs_facet_permutations: bool - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int, ...]]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] name_from_uflfile: str original_coefficient_positions: typing.List[int] @@ -240,7 +240,7 @@ def _compute_element_ir(element, element_numbers, finite_element_names): ir["basix_cell"] = element.cell_type ir["discontinuous"] = element.discontinuous ir["degree"] = element.degree - ir["value_shape"] = element.value_shape + ir["value_shape"] = [element.value_shape(ufl.domain.AbstractDomain(i, i)) for i in range(4)] ir["reference_value_shape"] = element.reference_value_shape ir["num_sub_elements"] = element.num_sub_elements @@ -567,7 +567,7 @@ def _compute_form_ir(form_data, form_id, prefix, form_names, integral_names, ele family = cmap.family_name degree = cmap.degree fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, - cmap.cell_type, cmap.lagrange_variant, el.value_shape(domain)) + cmap.cell_type, cmap.lagrange_variant) form_name = object_names.get(id(form_data.original_form), form_id) @@ -664,7 +664,8 @@ def _compute_expression_ir(expression, index, prefix, analysis, options, visuali cmap = domain.ufl_coordinate_element() family = cmap.family_name degree = cmap.degree - fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, el.value_shape(domain)) + fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, + cmap.cell_type, cmap.lagrange_variant) expression_name = object_names.get(id(original_expression), index) From 2cefc2df74d339c054fdcccd06b93caf8c549c22 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Fri, 26 Jan 2024 16:59:15 +0000 Subject: [PATCH 10/16] move value_shape to function spaces --- ffcx/codegeneration/C/expressions.py | 18 +++++++++++++++--- ffcx/codegeneration/C/finite_element.py | 16 ---------------- .../C/finite_element_template.py | 5 ----- ffcx/codegeneration/C/form.py | 15 +++++++++++++-- ffcx/codegeneration/C/form_template.py | 1 + ffcx/codegeneration/ufcx.h | 15 ++++++--------- ffcx/ir/representation.py | 12 ++++++------ 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index a7c514e92..30a6e1c11 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -95,10 +95,14 @@ def generator(ir, options): d["constant_names"] = "NULL" code = [] + vs_code = [] # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) - for (name, (element, dofmap, cmap_family, cmap_degree, cmap_celltype, cmap_variant)) in ir.function_spaces.items(): + for ( + name, + (element, dofmap, cmap_family, cmap_degree, cmap_celltype, cmap_variant, value_shape) + ) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] code += [f".finite_element = &{element},"] @@ -106,10 +110,18 @@ def generator(ir, options): code += [f".geometry_family = \"{cmap_family}\","] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] - code += [f".geometry_basix_variant = {int(cmap_variant)}"] + code += [f".geometry_basix_variant = {int(cmap_variant)},"] + code += [f".value_rank = {len(value_shape)},"] + if len(value_shape) == 0: + code += [".value_shape = NULL"] + else: + vs_code += [f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{", + " " + ", ".join([f"{i}" for i in value_shape]), + "};"] + code += [f".value_shape = value_shape_{name}_{ir.name_from_uflfile}"] code += ["};"] - d["function_spaces_alloc"] = "\n".join(code) + d["function_spaces_alloc"] = "\n".join(vs_code) + "\n" + "\n".join(code) d["function_spaces"] = "" if len(ir.function_spaces) > 0: diff --git a/ffcx/codegeneration/C/finite_element.py b/ffcx/codegeneration/C/finite_element.py index 2725e067e..79e3524ac 100644 --- a/ffcx/codegeneration/C/finite_element.py +++ b/ffcx/codegeneration/C/finite_element.py @@ -68,22 +68,6 @@ def generator(ir, options): d["reference_value_shape"] = "NULL" d["reference_value_shape_init"] = "" - rank = len(ir.value_shape[0]) - d["value_rank"] = rank - d["value_size"] = f"value_size_{ir.name}" - d["value_size_init"] = f"int value_size_{ir.name}[4] = {{" + ", ".join([ - f"{ufl.product(i)}" for i in ir.value_shape]) + "};" - d["value_shape"] = f"value_shape_{ir.name}" - d["value_shape_init"] = "" - if rank > 0: - for i in range(4): - d["value_shape_init"] += f"int value_shape_{ir.name}_{i}[{rank}] = {{" + ", ".join([ - f"{j}" for j in ir.value_shape[i]]) + "};\n" - d["value_shape_init"] += f"int* value_shape_{ir.name}[4] = {{" + ", ".join([ - f"value_shape_{ir.name}_{i}" for i in range(4)]) + "};" - else: - d["value_shape_init"] += f"int* value_shape_{ir.name}[4] = {{" + ", ".join(["NULL" for i in range(4)]) + "};" - if len(ir.sub_elements) > 0: d["sub_elements"] = f"sub_elements_{ir.name}" values = ", ".join(f"&{el}" for el in ir.sub_elements) diff --git a/ffcx/codegeneration/C/finite_element_template.py b/ffcx/codegeneration/C/finite_element_template.py index 06a835331..fab38174f 100644 --- a/ffcx/codegeneration/C/finite_element_template.py +++ b/ffcx/codegeneration/C/finite_element_template.py @@ -10,8 +10,6 @@ factory = """ // Code for element {factory_name} -{value_shape_init} -{value_size_init} {reference_value_shape_init} {sub_elements_init} {custom_element_init} @@ -27,9 +25,6 @@ .reference_value_rank = {reference_value_rank}, .reference_value_shape = {reference_value_shape}, .reference_value_size = {reference_value_size}, - .value_rank = {value_rank}, - .value_shape = {value_shape}, - .value_size = {value_size}, .degree = {degree}, .block_size = {block_size}, .basix_family = {basix_family}, diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index d4c854168..75ce011ac 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -115,6 +115,7 @@ def generator(ir, options): values = ", ".join(str(i) for i in integral_offsets) d["form_integral_offsets_init"] = f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};" + vs_code = [] code = [] # FIXME: Should be handled differently, revise how @@ -125,7 +126,8 @@ def generator(ir, options): cmap_family, cmap_degree, cmap_celltype, - cmap_variant + cmap_variant, + value_shape ) in ir.function_spaces.items(): code += [f"static ufcx_function_space functionspace_{name} ="] code += ["{"] @@ -134,7 +136,15 @@ def generator(ir, options): code += [f'.geometry_family = "{cmap_family}",'] code += [f".geometry_degree = {cmap_degree},"] code += [f".geometry_basix_cell = {int(cmap_celltype)},"] - code += [f".geometry_basix_variant = {int(cmap_variant)}"] + code += [f".geometry_basix_variant = {int(cmap_variant)},"] + code += [f".value_rank = {len(value_shape)},"] + if len(value_shape) == 0: + code += [".value_shape = NULL"] + else: + vs_code += [f"int value_shape_{ir.name}_{name}[{len(value_shape)}] = {{", + " " + ", ".join([f"{i}" for i in value_shape]), + "};"] + code += [f".value_shape = value_shape_{ir.name}_{name}"] code += ["};"] for name in ir.function_spaces.keys(): @@ -143,6 +153,7 @@ def generator(ir, options): code += ["return NULL;\n"] d["functionspace"] = "\n".join(code) + d["value_shape_init"] = "\n".join(vs_code) # Check that no keys are redundant or have been missed from string import Formatter diff --git a/ffcx/codegeneration/C/form_template.py b/ffcx/codegeneration/C/form_template.py index df0a5b61c..ee156f537 100644 --- a/ffcx/codegeneration/C/form_template.py +++ b/ffcx/codegeneration/C/form_template.py @@ -54,6 +54,7 @@ // Alias name ufcx_form* {name_from_uflfile} = &{factory_name}; +{value_shape_init} ufcx_function_space* functionspace_{name_from_uflfile}(const char* function_name) {{ {functionspace} diff --git a/ffcx/codegeneration/ufcx.h b/ffcx/codegeneration/ufcx.h index d8ec54722..0ae59821a 100644 --- a/ffcx/codegeneration/ufcx.h +++ b/ffcx/codegeneration/ufcx.h @@ -104,15 +104,6 @@ extern "C" /// Number of components of the reference value space int reference_value_size; - /// Rank of the value space - int value_rank; - - /// Shape of the value space for gdim 0 to 3 - int** value_shape; - - /// Dimension of the value space for gdim 0 to 3 - int* value_size; - /// Maximum polynomial degree of the finite element function space int degree; @@ -488,6 +479,12 @@ extern "C" /// The Basix variant of the finite element for the geometry map int geometry_basix_variant; + + /// Rank of the value space + int value_rank; + + /// Shape of the value space + int* value_shape; } ufcx_function_space; #ifdef __cplusplus diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index a3095360d..cbb681501 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -46,7 +46,7 @@ class FormIR(typing.NamedTuple): num_coefficients: int num_constants: int name_from_uflfile: str - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int]]] original_coefficient_position: typing.List[int] coefficient_names: typing.List[str] constant_names: typing.List[str] @@ -84,7 +84,6 @@ class ElementIR(typing.NamedTuple): cell_shape: str topological_dimension: int space_dimension: int - value_shape: typing.List[typing.Tuple[int, ...]] reference_value_shape: typing.Tuple[int, ...] degree: int num_sub_elements: int @@ -161,7 +160,7 @@ class ExpressionIR(typing.NamedTuple): coefficient_names: typing.List[str] constant_names: typing.List[str] needs_facet_permutations: bool - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int]]] name_from_uflfile: str original_coefficient_positions: typing.List[int] @@ -240,7 +239,6 @@ def _compute_element_ir(element, element_numbers, finite_element_names): ir["basix_cell"] = element.cell_type ir["discontinuous"] = element.discontinuous ir["degree"] = element.degree - ir["value_shape"] = [element.value_shape(ufl.domain.AbstractDomain(i, i)) for i in range(4)] ir["reference_value_shape"] = element.reference_value_shape ir["num_sub_elements"] = element.num_sub_elements @@ -566,8 +564,9 @@ def _compute_form_ir(form_data, form_id, prefix, form_names, integral_names, ele cmap._sub_element._variant = "equispaced" family = cmap.family_name degree = cmap.degree + value_shape = el.value_shape(domain) fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, - cmap.cell_type, cmap.lagrange_variant) + cmap.cell_type, cmap.lagrange_variant, value_shape) form_name = object_names.get(id(form_data.original_form), form_id) @@ -664,8 +663,9 @@ def _compute_expression_ir(expression, index, prefix, analysis, options, visuali cmap = domain.ufl_coordinate_element() family = cmap.family_name degree = cmap.degree + value_shape = el.value_shape(domain) fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, - cmap.cell_type, cmap.lagrange_variant) + cmap.cell_type, cmap.lagrange_variant, value_shape) expression_name = object_names.get(id(original_expression), index) From dcfa8d57787741cc43913e1a7f2fd907a2fe0af7 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Fri, 26 Jan 2024 17:34:04 +0000 Subject: [PATCH 11/16] flake --- ffcx/ir/representation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index cbb681501..3a5ce0f54 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -46,7 +46,8 @@ class FormIR(typing.NamedTuple): num_coefficients: int num_constants: int name_from_uflfile: str - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int]]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, + basix.LagrangeVariant, typing.Tuple[int]]] original_coefficient_position: typing.List[int] coefficient_names: typing.List[str] constant_names: typing.List[str] @@ -160,7 +161,8 @@ class ExpressionIR(typing.NamedTuple): coefficient_names: typing.List[str] constant_names: typing.List[str] needs_facet_permutations: bool - function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, typing.Tuple[int]]] + function_spaces: typing.Dict[str, typing.Tuple[str, str, str, int, basix.CellType, + basix.LagrangeVariant, typing.Tuple[int]]] name_from_uflfile: str original_coefficient_positions: typing.List[int] From 616f5c12f399fcd492be7a5871439f72d444d7ca Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Mon, 29 Jan 2024 15:21:09 +0000 Subject: [PATCH 12/16] move value shape to functionspace --- demo/FacetRestrictionAD.py | 2 +- demo/HyperElasticity.py | 2 +- ffcx/ir/representation.py | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/demo/FacetRestrictionAD.py b/demo/FacetRestrictionAD.py index 2ab29d1bc..cfaa188fe 100644 --- a/demo/FacetRestrictionAD.py +++ b/demo/FacetRestrictionAD.py @@ -16,7 +16,7 @@ # along with FFCx. If not, see . import basix.ufl from ufl import (Coefficient, FunctionSpace, Mesh, TestFunction, TrialFunction, - avg, derivative, dot, dS, dx, grad, inner) + avg, derivative, dS, dx, grad, inner) element = basix.ufl.element("Discontinuous Lagrange", "triangle", 1) domain = Mesh(basix.ufl.element("Lagrange", "triangle", 1, shape=(2, ))) diff --git a/demo/HyperElasticity.py b/demo/HyperElasticity.py index 159933c4a..99b17d24e 100644 --- a/demo/HyperElasticity.py +++ b/demo/HyperElasticity.py @@ -7,7 +7,7 @@ # Modified by Garth N. Wells, 2009 from ufl import (Coefficient, Constant, FacetNormal, FunctionSpace, Identity, Mesh, SpatialCoordinate, TestFunction, TrialFunction, - derivative, det, diff, dot, ds, dx, exp, grad, inner, inv, + derivative, det, diff, ds, dx, exp, grad, inner, inv, tetrahedron, tr, variable) # Cell and its properties diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index 3a5ce0f54..49ebb86f8 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -559,14 +559,15 @@ def _compute_form_ir(form_data, form_id, prefix, form_names, integral_names, ele if not str(name).isidentifier(): raise ValueError(f"Function name \"{name}\" must be a valid object identifier.") el = function.ufl_function_space().ufl_element() - domain = function.ufl_function_space().ufl_domain() + space = function.ufl_function_space() + domain = space.ufl_domain() cmap = domain.ufl_coordinate_element() # Default point spacing for CoordinateElement is equispaced if not isinstance(cmap, basix.ufl._ElementBase) and cmap.variant() is None: cmap._sub_element._variant = "equispaced" family = cmap.family_name degree = cmap.degree - value_shape = el.value_shape(domain) + value_shape = space.value_shape fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, cmap.cell_type, cmap.lagrange_variant, value_shape) @@ -661,11 +662,12 @@ def _compute_expression_ir(expression, index, prefix, analysis, options, visuali if not str(name).isidentifier(): raise ValueError(f"Function name \"{name}\" must be a valid object identifier.") el = function.ufl_function_space().ufl_element() - domain = function.ufl_function_space().ufl_domain() + space = function.ufl_function_space() + domain = space.ufl_domain() cmap = domain.ufl_coordinate_element() family = cmap.family_name degree = cmap.degree - value_shape = el.value_shape(domain) + value_shape = space.value_shape fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, cmap.cell_type, cmap.lagrange_variant, value_shape) From 41ed55ff30e4fcc61637ae24e5563e914272aecc Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Sat, 10 Feb 2024 10:22:06 +0000 Subject: [PATCH 13/16] ruff --- ffcx/codegeneration/C/expressions.py | 4 +++- ffcx/ir/representation.py | 4 ++-- test/test_tensor_product.py | 12 +----------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index 138866226..55276c3f4 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -106,7 +106,9 @@ def generator(ir, options): # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) - for name, (element, dofmap, cmap_family, cmap_degree, value_shape) in ir.function_spaces.items(): + for name, ( + element, dofmap, cmap_family, cmap_degree, value_shape, + ) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] code += [f".finite_element = &{element},"] diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index e47fb134e..54d5d7533 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -48,7 +48,7 @@ class FormIR(typing.NamedTuple): num_constants: int name_from_uflfile: str function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, - typing.Tuple[int]]] + tuple[int]]] original_coefficient_position: list[int] coefficient_names: list[str] constant_names: list[str] @@ -174,7 +174,7 @@ class ExpressionIR(typing.NamedTuple): constant_names: list[str] needs_facet_permutations: bool function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, - typing.Tuple[int]]] + tuple[int]]] name_from_uflfile: str original_coefficient_positions: list[int] diff --git a/test/test_tensor_product.py b/test/test_tensor_product.py index 5c503d14b..a5ef2a370 100644 --- a/test/test_tensor_product.py +++ b/test/test_tensor_product.py @@ -26,18 +26,8 @@ def cell_to_gdim(cell_type): def create_tensor_product_element(cell_type, degree, variant, shape=None): """Create tensor product element.""" family = basix.ElementFamily.P -<<<<<<< HEAD - ref = basix.create_element(family, cell_type, degree, variant) - factors = ref.get_tensor_product_representation()[0] - perm = factors[1] - dof_ordering = np.argsort(perm) - element = basix.create_element(family, cell_type, degree, variant, - dof_ordering=dof_ordering) - uflelement = basix.ufl._BasixElement(element) -======= element = basix.create_tp_element(family, cell_type, degree, variant) - uflelement = basix.ufl.wrap_element(element, gdim=gdim) ->>>>>>> main + uflelement = basix.ufl.wrap_element(element) if shape is None: return uflelement else: From bf82133198d49cbd7845cf5265a988c2f3520a60 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Sat, 10 Feb 2024 10:25:55 +0000 Subject: [PATCH 14/16] fix merge --- ffcx/codegeneration/C/expressions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index 55276c3f4..2461e82e0 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -107,7 +107,7 @@ def generator(ir, options): # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) for name, ( - element, dofmap, cmap_family, cmap_degree, value_shape, + element, dofmap, cmap_family, cmap_degree, cmap_celltype, cmap_variant, value_shape, ) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] From 76d2aab0966338b5ca78bd7e3f6e399275336395 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Sat, 10 Feb 2024 10:27:50 +0000 Subject: [PATCH 15/16] ruff format --- ffcx/codegeneration/C/expressions.py | 16 ++++++++++++---- ffcx/codegeneration/C/form.py | 10 ++++++---- ffcx/ir/representation.py | 21 +++++++++++++++------ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/ffcx/codegeneration/C/expressions.py b/ffcx/codegeneration/C/expressions.py index 2461e82e0..1f07cd208 100644 --- a/ffcx/codegeneration/C/expressions.py +++ b/ffcx/codegeneration/C/expressions.py @@ -107,7 +107,13 @@ def generator(ir, options): # FIXME: Should be handled differently, revise how # ufcx_function_space is generated (also for ufcx_form) for name, ( - element, dofmap, cmap_family, cmap_degree, cmap_celltype, cmap_variant, value_shape, + element, + dofmap, + cmap_family, + cmap_degree, + cmap_celltype, + cmap_variant, + value_shape, ) in ir.function_spaces.items(): code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="] code += ["{"] @@ -121,9 +127,11 @@ def generator(ir, options): if len(value_shape) == 0: code += [".value_shape = NULL"] else: - vs_code += [f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{", - " " + ", ".join([f"{i}" for i in value_shape]), - "};"] + vs_code += [ + f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{", + " " + ", ".join([f"{i}" for i in value_shape]), + "};", + ] code += [f".value_shape = value_shape_{name}_{ir.name_from_uflfile}"] code += ["};"] diff --git a/ffcx/codegeneration/C/form.py b/ffcx/codegeneration/C/form.py index 8638c7076..9c48059d6 100644 --- a/ffcx/codegeneration/C/form.py +++ b/ffcx/codegeneration/C/form.py @@ -139,7 +139,7 @@ def generator(ir, options): cmap_degree, cmap_celltype, cmap_variant, - value_shape + value_shape, ) in ir.function_spaces.items(): code += [f"static ufcx_function_space functionspace_{name} ="] code += ["{"] @@ -153,9 +153,11 @@ def generator(ir, options): if len(value_shape) == 0: code += [".value_shape = NULL"] else: - vs_code += [f"int value_shape_{ir.name}_{name}[{len(value_shape)}] = {{", - " " + ", ".join([f"{i}" for i in value_shape]), - "};"] + vs_code += [ + f"int value_shape_{ir.name}_{name}[{len(value_shape)}] = {{", + " " + ", ".join([f"{i}" for i in value_shape]), + "};", + ] code += [f".value_shape = value_shape_{ir.name}_{name}"] code += ["};"] diff --git a/ffcx/ir/representation.py b/ffcx/ir/representation.py index 54d5d7533..f27862962 100644 --- a/ffcx/ir/representation.py +++ b/ffcx/ir/representation.py @@ -47,8 +47,9 @@ class FormIR(typing.NamedTuple): num_coefficients: int num_constants: int name_from_uflfile: str - function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, - tuple[int]]] + function_spaces: dict[ + str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, tuple[int]] + ] original_coefficient_position: list[int] coefficient_names: list[str] constant_names: list[str] @@ -173,8 +174,9 @@ class ExpressionIR(typing.NamedTuple): coefficient_names: list[str] constant_names: list[str] needs_facet_permutations: bool - function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, - tuple[int]]] + function_spaces: dict[ + str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, tuple[int]] + ] name_from_uflfile: str original_coefficient_positions: list[int] @@ -790,8 +792,15 @@ def _compute_expression_ir( family = cmap.family_name degree = cmap.degree value_shape = space.value_shape - fs[name] = (finite_element_names[el], dofmap_names[el], family, degree, - cmap.cell_type, cmap.lagrange_variant, value_shape) + fs[name] = ( + finite_element_names[el], + dofmap_names[el], + family, + degree, + cmap.cell_type, + cmap.lagrange_variant, + value_shape, + ) expression_name = object_names.get(id(original_expression), index) From 80f63e65604e8b90e14db617be615611b4494554 Mon Sep 17 00:00:00 2001 From: Matthew Scroggs Date: Sat, 10 Feb 2024 10:55:15 +0000 Subject: [PATCH 16/16] branches --- .github/workflows/dolfinx-tests.yml | 6 +++--- .github/workflows/pythonapp.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dolfinx-tests.yml b/.github/workflows/dolfinx-tests.yml index 7350f7c2f..8cb2d9006 100644 --- a/.github/workflows/dolfinx-tests.yml +++ b/.github/workflows/dolfinx-tests.yml @@ -35,8 +35,8 @@ jobs: - name: Install UFL and Basix (default branches/tags) if: github.event_name != 'workflow_dispatch' run: | - python3 -m pip install git+https://github.com/FEniCS/ufl.git@mscroggs/gdim - python3 -m pip install git+https://github.com/FEniCS/basix.git@mscroggs/remove-gdim + python3 -m pip install git+https://github.com/FEniCS/ufl.git + python3 -m pip install git+https://github.com/FEniCS/basix.git - name: Install UFL and Basix (specified branches/tags) if: github.event_name == 'workflow_dispatch' run: | @@ -51,7 +51,7 @@ jobs: with: path: ./dolfinx repository: FEniCS/dolfinx - ref: mscroggs/gdim + ref: main - name: Get DOLFINx source (specified branch/tag) if: github.event_name == 'workflow_dispatch' uses: actions/checkout@v4 diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 05138cd96..cc1c704bf 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -38,8 +38,8 @@ jobs: run: brew install graphviz ninja pkg-config - name: Install FEniCS dependencies (Python) run: | - pip install git+https://github.com/FEniCS/ufl.git@mscroggs/gdim - pip install git+https://github.com/FEniCS/basix.git@mscroggs/remove-gdim + pip install git+https://github.com/FEniCS/ufl.git + pip install git+https://github.com/FEniCS/basix.git - name: Install FFCx run: pip install .[ci] - name: Static check with mypy