Skip to content

Commit 7bc8be7

Browse files
authored
Remove information about physical cells from elements (#653)
* remove information about physical elements from ffc element * branches * update more tests * update demos * reference value shapes * dolfinx branch * Add value shape to function spaces * adding value_shape[dim] to finite element * write value_shape for each gdim into generated code * move value_shape to function spaces * flake * move value shape to functionspace * ruff * fix merge * ruff format * branches
1 parent ef6c390 commit 7bc8be7

13 files changed

+84
-74
lines changed

demo/HyperElasticity.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
# Cell and its properties
3232
cell = tetrahedron
33-
d = cell.geometric_dimension()
33+
d = 3
3434

3535
# Elements
3636
u_element = basix.ufl.element("P", cell.cellname(), 2, shape=(3,))

demo/ProjectionManifold.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
from ufl import FunctionSpace, Mesh, TestFunctions, TrialFunctions, div, dx, inner
2525

2626
# Define element over this domain
27-
V = basix.ufl.element("RT", "triangle", 1, gdim=3)
28-
Q = basix.ufl.element("DG", "triangle", 0, gdim=3)
27+
V = basix.ufl.element("RT", "triangle", 1)
28+
Q = basix.ufl.element("DG", "triangle", 0)
2929
element = basix.ufl.mixed_element([V, Q])
30-
domain = Mesh(basix.ufl.element("Lagrange", "triangle", 1, shape=(3,), gdim=3))
30+
domain = Mesh(basix.ufl.element("Lagrange", "triangle", 1, shape=(3,)))
3131
space = FunctionSpace(domain, element)
3232

3333
(u, p) = TrialFunctions(space)

ffcx/codegeneration/C/expressions.py

+24-3
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,40 @@ def generator(ir, options):
102102
d["constant_names"] = "NULL"
103103

104104
code = []
105+
vs_code = []
105106

106107
# FIXME: Should be handled differently, revise how
107108
# ufcx_function_space is generated (also for ufcx_form)
108-
for name, (element, dofmap, cmap_family, cmap_degree) in ir.function_spaces.items():
109+
for name, (
110+
element,
111+
dofmap,
112+
cmap_family,
113+
cmap_degree,
114+
cmap_celltype,
115+
cmap_variant,
116+
value_shape,
117+
) in ir.function_spaces.items():
109118
code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="]
110119
code += ["{"]
111120
code += [f".finite_element = &{element},"]
112121
code += [f".dofmap = &{dofmap},"]
113122
code += [f'.geometry_family = "{cmap_family}",']
114-
code += [f".geometry_degree = {cmap_degree}"]
123+
code += [f".geometry_degree = {cmap_degree},"]
124+
code += [f".geometry_basix_cell = {int(cmap_celltype)},"]
125+
code += [f".geometry_basix_variant = {int(cmap_variant)},"]
126+
code += [f".value_rank = {len(value_shape)},"]
127+
if len(value_shape) == 0:
128+
code += [".value_shape = NULL"]
129+
else:
130+
vs_code += [
131+
f"int value_shape_{name}_{ir.name_from_uflfile}[{len(value_shape)}] = {{",
132+
" " + ", ".join([f"{i}" for i in value_shape]),
133+
"};",
134+
]
135+
code += [f".value_shape = value_shape_{name}_{ir.name_from_uflfile}"]
115136
code += ["};"]
116137

117-
d["function_spaces_alloc"] = "\n".join(code)
138+
d["function_spaces_alloc"] = "\n".join(vs_code) + "\n" + "\n".join(code)
118139
d["function_spaces"] = ""
119140

120141
if len(ir.function_spaces) > 0:

ffcx/codegeneration/C/finite_element.py

+1-13
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,16 @@ def generator(ir, options):
2525
"""Generate UFC code for a finite element."""
2626
logger.info("Generating code for finite element:")
2727
logger.info(f"--- degree: {ir.degree}")
28-
logger.info(f"--- value shape: {ir.value_shape}")
28+
logger.info(f"--- value shape: {ir.reference_value_shape}")
2929
logger.info(f"--- name: {ir.name}")
3030

3131
d = {}
3232
d["factory_name"] = ir.name
3333
d["signature"] = f'"{ir.signature}"'
34-
d["geometric_dimension"] = ir.geometric_dimension
3534
d["topological_dimension"] = ir.topological_dimension
3635
d["cell_shape"] = ir.cell_shape
3736
d["element_type"] = ir.element_type
3837
d["space_dimension"] = ir.space_dimension
39-
d["value_rank"] = len(ir.value_shape)
40-
d["value_size"] = ufl.product(ir.value_shape)
4138
d["reference_value_rank"] = len(ir.reference_value_shape)
4239
d["reference_value_size"] = ufl.product(ir.reference_value_shape)
4340
d["degree"] = ir.degree
@@ -64,15 +61,6 @@ def generator(ir, options):
6461
else:
6562
d["basix_cell"] = int(ir.basix_cell)
6663

67-
if len(ir.value_shape) > 0:
68-
d["value_shape"] = f"value_shape_{ir.name}"
69-
values = ", ".join(str(i) for i in ir.value_shape)
70-
sizes = len(ir.value_shape)
71-
d["value_shape_init"] = f"int value_shape_{ir.name}[{sizes}] = {{{values}}};"
72-
else:
73-
d["value_shape"] = "NULL"
74-
d["value_shape_init"] = ""
75-
7664
if len(ir.reference_value_shape) > 0:
7765
d["reference_value_shape"] = f"reference_value_shape_{ir.name}"
7866
values = ", ".join(str(i) for i in ir.reference_value_shape)

ffcx/codegeneration/C/finite_element_template.py

-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
factory = """
1212
// Code for element {factory_name}
1313
14-
{value_shape_init}
1514
{reference_value_shape_init}
1615
{sub_elements_init}
1716
{custom_element_init}
@@ -23,11 +22,7 @@
2322
.cell_shape = {cell_shape},
2423
.element_type = {element_type},
2524
.topological_dimension = {topological_dimension},
26-
.geometric_dimension = {geometric_dimension},
2725
.space_dimension = {space_dimension},
28-
.value_rank = {value_rank},
29-
.value_shape = {value_shape},
30-
.value_size = {value_size},
3126
.reference_value_rank = {reference_value_rank},
3227
.reference_value_shape = {reference_value_shape},
3328
.reference_value_size = {reference_value_size},

ffcx/codegeneration/C/form.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def generator(ir, options):
127127
"form_integral_offsets_init"
128128
] = f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};"
129129

130+
vs_code = []
130131
code = []
131132

132133
# FIXME: Should be handled differently, revise how
@@ -138,6 +139,7 @@ def generator(ir, options):
138139
cmap_degree,
139140
cmap_celltype,
140141
cmap_variant,
142+
value_shape,
141143
) in ir.function_spaces.items():
142144
code += [f"static ufcx_function_space functionspace_{name} ="]
143145
code += ["{"]
@@ -146,7 +148,17 @@ def generator(ir, options):
146148
code += [f'.geometry_family = "{cmap_family}",']
147149
code += [f".geometry_degree = {cmap_degree},"]
148150
code += [f".geometry_basix_cell = {int(cmap_celltype)},"]
149-
code += [f".geometry_basix_variant = {int(cmap_variant)}"]
151+
code += [f".geometry_basix_variant = {int(cmap_variant)},"]
152+
code += [f".value_rank = {len(value_shape)},"]
153+
if len(value_shape) == 0:
154+
code += [".value_shape = NULL"]
155+
else:
156+
vs_code += [
157+
f"int value_shape_{ir.name}_{name}[{len(value_shape)}] = {{",
158+
" " + ", ".join([f"{i}" for i in value_shape]),
159+
"};",
160+
]
161+
code += [f".value_shape = value_shape_{ir.name}_{name}"]
150162
code += ["};"]
151163

152164
for name in ir.function_spaces.keys():
@@ -155,6 +167,7 @@ def generator(ir, options):
155167
code += ["return NULL;\n"]
156168

157169
d["functionspace"] = "\n".join(code)
170+
d["value_shape_init"] = "\n".join(vs_code)
158171

159172
# Check that no keys are redundant or have been missed
160173
from string import Formatter

ffcx/codegeneration/C/form_template.py

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
// Alias name
5656
ufcx_form* {name_from_uflfile} = &{factory_name};
5757
58+
{value_shape_init}
5859
ufcx_function_space* functionspace_{name_from_uflfile}(const char* function_name)
5960
{{
6061
{functionspace}

ffcx/codegeneration/access.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,10 @@ def cell_vertices(self, mt, tabledata, num_points):
293293

294294
# Get dimension and dofmap of scalar element
295295
assert isinstance(coordinate_element, basix.ufl._BlockedElement)
296-
assert coordinate_element.value_shape == (gdim,)
296+
assert coordinate_element.reference_value_shape == (gdim,)
297297
(ufl_scalar_element,) = set(coordinate_element.sub_elements)
298298
scalar_element = ufl_scalar_element
299-
assert scalar_element.value_size == 1 and scalar_element.block_size == 1
299+
assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1
300300

301301
vertex_scalar_dofs = scalar_element.entity_dofs[0]
302302
num_scalar_dofs = scalar_element.dim
@@ -327,10 +327,10 @@ def cell_edge_vectors(self, mt, tabledata, num_points):
327327

328328
# Get dimension and dofmap of scalar element
329329
assert isinstance(coordinate_element, basix.ufl._BlockedElement)
330-
assert coordinate_element.value_shape == (gdim,)
330+
assert coordinate_element.reference_value_shape == (gdim,)
331331
(ufl_scalar_element,) = set(coordinate_element.sub_elements)
332332
scalar_element = ufl_scalar_element
333-
assert scalar_element.value_size == 1 and scalar_element.block_size == 1
333+
assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1
334334

335335
vertex_scalar_dofs = scalar_element.entity_dofs[0]
336336
num_scalar_dofs = scalar_element.dim
@@ -367,10 +367,10 @@ def facet_edge_vectors(self, mt, tabledata, num_points):
367367

368368
# Get dimension and dofmap of scalar element
369369
assert isinstance(coordinate_element, basix.ufl._BlockedElement)
370-
assert coordinate_element.value_shape == (gdim,)
370+
assert coordinate_element.reference_value_shape == (gdim,)
371371
(ufl_scalar_element,) = set(coordinate_element.sub_elements)
372372
scalar_element = ufl_scalar_element
373-
assert scalar_element.value_size == 1 and scalar_element.block_size == 1
373+
assert scalar_element.reference_value_size == 1 and scalar_element.block_size == 1
374374

375375
scalar_element = ufl_scalar_element
376376
num_scalar_dofs = scalar_element.dim

ffcx/codegeneration/ufcx.h

+6-12
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,9 @@ extern "C"
9292
/// Topological dimension of the cell
9393
int topological_dimension;
9494

95-
/// Geometric dimension of the cell
96-
int geometric_dimension;
97-
9895
/// Dimension of the finite element function space
9996
int space_dimension;
10097

101-
/// Rank of the value space
102-
int value_rank;
103-
104-
/// Dimension of the value space for axis i
105-
int* value_shape;
106-
107-
/// Number of components of the value space
108-
int value_size;
109-
11098
/// Rank of the reference value space
11199
int reference_value_rank;
112100

@@ -479,6 +467,12 @@ extern "C"
479467

480468
/// The Basix variant of the finite element for the geometry map
481469
int geometry_basix_variant;
470+
471+
/// Rank of the value space
472+
int value_rank;
473+
474+
/// Shape of the value space
475+
int* value_shape;
482476
} ufcx_function_space;
483477

484478
#ifdef __cplusplus

ffcx/ir/representation.py

+24-9
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class FormIR(typing.NamedTuple):
4747
num_coefficients: int
4848
num_constants: int
4949
name_from_uflfile: str
50-
function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]]
50+
function_spaces: dict[
51+
str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, tuple[int]]
52+
]
5153
original_coefficient_position: list[int]
5254
coefficient_names: list[str]
5355
constant_names: list[str]
@@ -90,9 +92,7 @@ class ElementIR(typing.NamedTuple):
9092
signature: str
9193
cell_shape: str
9294
topological_dimension: int
93-
geometric_dimension: int
9495
space_dimension: int
95-
value_shape: tuple[int, ...]
9696
reference_value_shape: tuple[int, ...]
9797
degree: int
9898
num_sub_elements: int
@@ -174,7 +174,9 @@ class ExpressionIR(typing.NamedTuple):
174174
coefficient_names: list[str]
175175
constant_names: list[str]
176176
needs_facet_permutations: bool
177-
function_spaces: dict[str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant]]
177+
function_spaces: dict[
178+
str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, tuple[int]]
179+
]
178180
name_from_uflfile: str
179181
original_coefficient_positions: list[int]
180182

@@ -289,7 +291,6 @@ def _compute_element_ir(element, element_numbers, finite_element_names):
289291
ir["signature"] = repr(element)
290292
ir["cell_shape"] = element.cell_type.name
291293
ir["topological_dimension"] = cell.topological_dimension()
292-
ir["geometric_dimension"] = cell.geometric_dimension()
293294
ir["space_dimension"] = element.dim + element.num_global_support_dofs
294295
ir["element_type"] = element.ufcx_element_type
295296
ir["lagrange_variant"] = element.lagrange_variant
@@ -298,7 +299,6 @@ def _compute_element_ir(element, element_numbers, finite_element_names):
298299
ir["basix_cell"] = element.cell_type
299300
ir["discontinuous"] = element.discontinuous
300301
ir["degree"] = element.degree
301-
ir["value_shape"] = element.value_shape
302302
ir["reference_value_shape"] = element.reference_value_shape
303303

304304
ir["num_sub_elements"] = element.num_sub_elements
@@ -662,19 +662,23 @@ def _compute_form_ir(
662662
if not str(name).isidentifier():
663663
raise ValueError(f'Function name "{name}" must be a valid object identifier.')
664664
el = function.ufl_function_space().ufl_element()
665-
cmap = function.ufl_function_space().ufl_domain().ufl_coordinate_element()
665+
space = function.ufl_function_space()
666+
domain = space.ufl_domain()
667+
cmap = domain.ufl_coordinate_element()
666668
# Default point spacing for CoordinateElement is equispaced
667669
if not isinstance(cmap, basix.ufl._ElementBase) and cmap.variant() is None:
668670
cmap._sub_element._variant = "equispaced"
669671
family = cmap.family_name
670672
degree = cmap.degree
673+
value_shape = space.value_shape
671674
fs[name] = (
672675
finite_element_names[el],
673676
dofmap_names[el],
674677
family,
675678
degree,
676679
cmap.cell_type,
677680
cmap.lagrange_variant,
681+
value_shape,
678682
)
679683

680684
form_name = object_names.get(id(form_data.original_form), form_id)
@@ -782,10 +786,21 @@ def _compute_expression_ir(
782786
if not str(name).isidentifier():
783787
raise ValueError(f'Function name "{name}" must be a valid object identifier.')
784788
el = function.ufl_function_space().ufl_element()
785-
cmap = function.ufl_function_space().ufl_domain().ufl_coordinate_element()
789+
space = function.ufl_function_space()
790+
domain = space.ufl_domain()
791+
cmap = domain.ufl_coordinate_element()
786792
family = cmap.family_name
787793
degree = cmap.degree
788-
fs[name] = (finite_element_names[el], dofmap_names[el], family, degree)
794+
value_shape = space.value_shape
795+
fs[name] = (
796+
finite_element_names[el],
797+
dofmap_names[el],
798+
family,
799+
degree,
800+
cmap.cell_type,
801+
cmap.lagrange_variant,
802+
value_shape,
803+
)
789804

790805
expression_name = object_names.get(id(original_expression), index)
791806

test/test_blocked_elements.py

-16
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ def test_finite_element(compile_args):
1919
ufcx_element, ufcx_dofmap = jit_compiled_elements[0]
2020

2121
assert ufcx_element.topological_dimension == 2
22-
assert ufcx_element.geometric_dimension == 2
2322
assert ufcx_element.space_dimension == 3
24-
assert ufcx_element.value_rank == 0
25-
assert ufcx_element.value_size == 1
2623
assert ufcx_element.reference_value_rank == 0
2724
assert ufcx_element.reference_value_size == 1
2825
assert ufcx_element.block_size == 1
@@ -48,11 +45,7 @@ def test_vector_element(compile_args):
4845
ufcx_element, ufcx_dofmap = jit_compiled_elements[0]
4946

5047
assert ufcx_element.topological_dimension == 2
51-
assert ufcx_element.geometric_dimension == 2
5248
assert ufcx_element.space_dimension == 6
53-
assert ufcx_element.value_rank == 1
54-
assert ufcx_element.value_shape[0] == 2
55-
assert ufcx_element.value_size == 2
5649
assert ufcx_element.reference_value_rank == 1
5750
assert ufcx_element.reference_value_shape[0] == 2
5851
assert ufcx_element.reference_value_size == 2
@@ -79,12 +72,7 @@ def test_tensor_element(compile_args):
7972
ufcx_element, ufcx_dofmap = jit_compiled_elements[0]
8073

8174
assert ufcx_element.topological_dimension == 2
82-
assert ufcx_element.geometric_dimension == 2
8375
assert ufcx_element.space_dimension == 12
84-
assert ufcx_element.value_rank == 2
85-
assert ufcx_element.value_shape[0] == 2
86-
assert ufcx_element.value_shape[1] == 2
87-
assert ufcx_element.value_size == 4
8876
assert ufcx_element.reference_value_rank == 2
8977
assert ufcx_element.reference_value_shape[0] == 2
9078
assert ufcx_element.reference_value_shape[1] == 2
@@ -114,11 +102,7 @@ def test_vector_quadrature_element(compile_args):
114102
ufcx_element, ufcx_dofmap = jit_compiled_elements[0]
115103

116104
assert ufcx_element.topological_dimension == 3
117-
assert ufcx_element.geometric_dimension == 3
118105
assert ufcx_element.space_dimension == 12
119-
assert ufcx_element.value_rank == 1
120-
assert ufcx_element.value_shape[0] == 3
121-
assert ufcx_element.value_size == 3
122106
assert ufcx_element.reference_value_rank == 1
123107
assert ufcx_element.reference_value_shape[0] == 3
124108
assert ufcx_element.reference_value_size == 3

0 commit comments

Comments
 (0)