Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/HyperElasticity.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,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,))
Expand Down
6 changes: 3 additions & 3 deletions demo/ProjectionManifold.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
from ufl import FunctionSpace, Mesh, TestFunctions, TrialFunctions, div, dx, 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)
Expand Down
27 changes: 24 additions & 3 deletions ffcx/codegeneration/C/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,40 @@ 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) 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},"]
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)},"]
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:
Expand Down
14 changes: 1 addition & 13 deletions ffcx/codegeneration/C/finite_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,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
Expand All @@ -64,15 +61,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)
Expand Down
5 changes: 0 additions & 5 deletions ffcx/codegeneration/C/finite_element_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
factory = """
// Code for element {factory_name}

{value_shape_init}
{reference_value_shape_init}
{sub_elements_init}
{custom_element_init}
Expand All @@ -23,11 +22,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},
Expand Down
15 changes: 14 additions & 1 deletion ffcx/codegeneration/C/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def generator(ir, options):
"form_integral_offsets_init"
] = f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};"

vs_code = []
code = []

# FIXME: Should be handled differently, revise how
Expand All @@ -138,6 +139,7 @@ def generator(ir, options):
cmap_degree,
cmap_celltype,
cmap_variant,
value_shape,
) in ir.function_spaces.items():
code += [f"static ufcx_function_space functionspace_{name} ="]
code += ["{"]
Expand All @@ -146,7 +148,17 @@ 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():
Expand All @@ -155,6 +167,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
Expand Down
1 change: 1 addition & 0 deletions ffcx/codegeneration/C/form_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,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}
Expand Down
12 changes: 6 additions & 6 deletions ffcx/codegeneration/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,10 @@ def cell_vertices(self, 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
Expand Down Expand Up @@ -327,10 +327,10 @@ def cell_edge_vectors(self, 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
Expand Down Expand Up @@ -367,10 +367,10 @@ def facet_edge_vectors(self, 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
Expand Down
18 changes: 6 additions & 12 deletions ffcx/codegeneration/ufcx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -479,6 +467,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
Expand Down
33 changes: 24 additions & 9 deletions ffcx/ir/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +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]]
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]
Expand Down Expand Up @@ -90,9 +92,7 @@ class ElementIR(typing.NamedTuple):
signature: str
cell_shape: str
topological_dimension: int
geometric_dimension: int
space_dimension: int
value_shape: tuple[int, ...]
reference_value_shape: tuple[int, ...]
degree: int
num_sub_elements: int
Expand Down Expand Up @@ -174,7 +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]]
function_spaces: dict[
str, tuple[str, str, str, int, basix.CellType, basix.LagrangeVariant, tuple[int]]
]
name_from_uflfile: str
original_coefficient_positions: list[int]

Expand Down Expand Up @@ -289,7 +291,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
Expand All @@ -298,7 +299,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
ir["reference_value_shape"] = element.reference_value_shape

ir["num_sub_elements"] = element.num_sub_elements
Expand Down Expand Up @@ -662,19 +662,23 @@ def _compute_form_ir(
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()
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 = space.value_shape
fs[name] = (
finite_element_names[el],
dofmap_names[el],
family,
degree,
cmap.cell_type,
cmap.lagrange_variant,
value_shape,
)

form_name = object_names.get(id(form_data.original_form), form_id)
Expand Down Expand Up @@ -782,10 +786,21 @@ def _compute_expression_ir(
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()
space = function.ufl_function_space()
domain = 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)
value_shape = space.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)

Expand Down
16 changes: 0 additions & 16 deletions test/test_blocked_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,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
Expand All @@ -48,11 +45,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
Expand All @@ -79,12 +72,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
Expand Down Expand Up @@ -114,11 +102,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
Expand Down
Loading