Skip to content

Commit

Permalink
Merge branch 'main' into mscroggs/move-QuadratureElement
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisrichardson authored Aug 25, 2023
2 parents 15422f9 + 4572bec commit ff66e31
Show file tree
Hide file tree
Showing 16 changed files with 282 additions and 372 deletions.
75 changes: 0 additions & 75 deletions ffcx/codegeneration/C/cnodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1459,81 +1459,6 @@ def flops(self):
return 0


def _is_simple_if_body(body):
if isinstance(body, StatementList):
if len(body.statements) > 1:
return False
(body,) = body.statements
return isinstance(body, (Return, AssignOp))


class If(CStatement):
__slots__ = ("condition", "body")
is_scoped = True

def __init__(self, condition, body):
self.condition = as_cexpr(condition)
self.body = as_cstatement(body)

def cs_format(self, precision=None):
statement = "if (" + self.condition.ce_format(precision) + ")"
body_fmt = Indented(self.body.cs_format(precision))
if _is_simple_if_body(self.body):
return (statement, body_fmt)
else:
return (statement, "{", body_fmt, "}")

def __eq__(self, other):
return (
isinstance(other, type(self))
and self.condition == other.condition
and self.body == other.body
)


class ElseIf(CStatement):
__slots__ = ("condition", "body")
is_scoped = True

def __init__(self, condition, body):
self.condition = as_cexpr(condition)
self.body = as_cstatement(body)

def cs_format(self, precision=None):
statement = "else if (" + self.condition.ce_format(precision) + ")"
body_fmt = Indented(self.body.cs_format(precision))
if _is_simple_if_body(self.body):
return (statement, body_fmt)
else:
return (statement, "{", body_fmt, "}")

def __eq__(self, other):
return (
isinstance(other, type(self))
and self.condition == other.condition
and self.body == other.body
)


class Else(CStatement):
__slots__ = ("body",)
is_scoped = True

def __init__(self, body):
self.body = as_cstatement(body)

def cs_format(self, precision=None):
statement = "else"
body_fmt = Indented(self.body.cs_format(precision))
if _is_simple_if_body(self.body):
return (statement, body_fmt)
else:
return (statement, "{", body_fmt, "}")

def __eq__(self, other):
return isinstance(other, type(self)) and self.body == other.body


def is_simple_inner_loop(code):
if isinstance(code, ForRange) and is_simple_inner_loop(code.body):
return True
Expand Down
49 changes: 16 additions & 33 deletions ffcx/codegeneration/dofmap.py → ffcx/codegeneration/C/dofmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import logging

import ffcx.codegeneration.dofmap_template as ufcx_dofmap
import ffcx.codegeneration.C.dofmap_template as ufcx_dofmap

logger = logging.getLogger("ffcx")

Expand All @@ -29,8 +29,6 @@ def generator(ir, options):
d["num_element_support_dofs"] = ir.num_element_support_dofs
d["num_sub_dofmaps"] = ir.num_sub_dofmaps

import ffcx.codegeneration.C.cnodes as L

flattened_entity_dofs = []
entity_dof_offsets = [0]
for dim in ir.entity_dofs:
Expand All @@ -39,19 +37,13 @@ def generator(ir, options):
flattened_entity_dofs.append(v)
entity_dof_offsets.append(len(flattened_entity_dofs))
d["entity_dofs"] = f"entity_dofs_{ir.name}"
d["entity_dofs_init"] = L.ArrayDecl(
"int",
f"entity_dofs_{ir.name}",
values=flattened_entity_dofs,
sizes=len(flattened_entity_dofs),
)
values = ", ".join(str(i) for i in flattened_entity_dofs)
sizes = len(flattened_entity_dofs)
d["entity_dofs_init"] = f"int entity_dofs_{ir.name}[{sizes}] = {{{values}}};"
d["entity_dof_offsets"] = f"entity_dof_offsets_{ir.name}"
d["entity_dof_offsets_init"] = L.ArrayDecl(
"int",
f"entity_dof_offsets_{ir.name}",
values=entity_dof_offsets,
sizes=len(entity_dof_offsets),
)
values = ", ".join(str(i) for i in entity_dof_offsets)
sizes = len(entity_dof_offsets)
d["entity_dof_offsets_init"] = f"int entity_dof_offsets_{ir.name}[{sizes}] = {{{values}}};"

# Closure
flattened_entity_closure_dofs = []
Expand All @@ -62,29 +54,20 @@ def generator(ir, options):
flattened_entity_closure_dofs.append(v)
entity_closure_dof_offsets.append(len(flattened_entity_closure_dofs))
d["entity_closure_dofs"] = f"entity_closure_dofs_{ir.name}"
d["entity_closure_dofs_init"] = L.ArrayDecl(
"int",
f"entity_closure_dofs_{ir.name}",
values=flattened_entity_closure_dofs,
sizes=len(flattened_entity_closure_dofs),
)
values = ", ".join(str(i) for i in flattened_entity_closure_dofs)
sizes = len(flattened_entity_closure_dofs)
d["entity_closure_dofs_init"] = f"int entity_closure_dofs_{ir.name}[{sizes}] = {{{values}}};"
d["entity_closure_dof_offsets"] = f"entity_closure_dof_offsets_{ir.name}"
d["entity_closure_dof_offsets_init"] = L.ArrayDecl(
"int",
f"entity_closure_dof_offsets_{ir.name}",
values=entity_closure_dof_offsets,
sizes=len(entity_closure_dof_offsets),
)
values = ", ".join(str(i) for i in entity_closure_dof_offsets)
sizes = len(entity_dof_offsets)
d["entity_closure_dof_offsets_init"] = f"int entity_closure_dof_offsets_{ir.name}[{sizes}] = {{{values}}};"

d["block_size"] = ir.block_size

if len(ir.sub_dofmaps) > 0:
d["sub_dofmaps_initialization"] = L.ArrayDecl(
"ufcx_dofmap*",
f"sub_dofmaps_{ir.name}",
values=[L.AddressOf(L.Symbol(dofmap)) for dofmap in ir.sub_dofmaps],
sizes=len(ir.sub_dofmaps),
)
values = ", ".join(f"&{dofmap}" for dofmap in ir.sub_dofmaps)
sizes = len(ir.sub_dofmaps)
d["sub_dofmaps_initialization"] = f"ufcx_dofmap* sub_dofmaps_{ir.name}[{sizes}] = {{{values}}};"
d["sub_dofmaps"] = f"sub_dofmaps_{ir.name}"
else:
d["sub_dofmaps_initialization"] = ""
Expand Down
File renamed without changes.
129 changes: 129 additions & 0 deletions ffcx/codegeneration/C/expressions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright (C) 2019 Michal Habera
#
# This file is part of FFCx.(https://www.fenicsproject.org)
#
# SPDX-License-Identifier: LGPL-3.0-or-later

import logging

from ffcx.codegeneration.C import expressions_template
from ffcx.codegeneration.expression_generator import ExpressionGenerator
from ffcx.codegeneration.backend import FFCXBackend
from ffcx.codegeneration.C.format_lines import format_indented_lines
from ffcx.naming import cdtype_to_numpy, scalar_to_value_type

logger = logging.getLogger("ffcx")


def generator(ir, options):
"""Generate UFC code for an expression."""
logger.info("Generating code for expression:")
logger.info(f"--- points: {ir.points}")
logger.info(f"--- name: {ir.name}")

factory_name = ir.name

# Format declaration
declaration = expressions_template.declaration.format(
factory_name=factory_name, name_from_uflfile=ir.name_from_uflfile)

backend = FFCXBackend(ir, options)
eg = ExpressionGenerator(ir, backend)

d = {}
d["name_from_uflfile"] = ir.name_from_uflfile
d["factory_name"] = ir.name

parts = eg.generate()

body = format_indented_lines(parts.cs_format(), 1)
d["tabulate_expression"] = body

if len(ir.original_coefficient_positions) > 0:
d["original_coefficient_positions"] = f"original_coefficient_positions_{ir.name}"
values = ", ".join(str(i) for i in ir.original_coefficient_positions)
sizes = len(ir.original_coefficient_positions)
d["original_coefficient_positions_init"] = \
f"static int original_coefficient_positions_{ir.name}[{sizes}] = {{{values}}};"
else:
d["original_coefficient_positions"] = "NULL"
d["original_coefficient_positions_init"] = ""

values = ", ".join(str(p) for p in ir.points.flatten())
sizes = ir.points.size
d["points_init"] = f"static double points_{ir.name}[{sizes}] = {{{values}}};"
d["points"] = f"points_{ir.name}"

if len(ir.expression_shape) > 0:
values = ", ".join(str(i) for i in ir.expression_shape)
sizes = len(ir.expression_shape)
d["value_shape_init"] = f"static int value_shape_{ir.name}[{sizes}] = {{{values}}};"
d["value_shape"] = f"value_shape_{ir.name}"
else:
d["value_shape_init"] = ""
d["value_shape"] = "NULL"

d["num_components"] = len(ir.expression_shape)
d["num_coefficients"] = len(ir.coefficient_numbering)
d["num_constants"] = len(ir.constant_names)
d["num_points"] = ir.points.shape[0]
d["topological_dimension"] = ir.points.shape[1]
d["scalar_type"] = options["scalar_type"]
d["geom_type"] = scalar_to_value_type(options["scalar_type"])
d["np_scalar_type"] = cdtype_to_numpy(options["scalar_type"])

d["rank"] = len(ir.tensor_shape)

if len(ir.coefficient_names) > 0:
values = ", ".join(f'"{name}"' for name in ir.coefficient_names)
sizes = len(ir.coefficient_names)
d["coefficient_names_init"] = f"static const char* coefficient_names_{ir.name}[{sizes}] = {{{values}}};"
d["coefficient_names"] = f"coefficient_names_{ir.name}"
else:
d["coefficient_names_init"] = ""
d["coefficient_names"] = "NULL"

if len(ir.constant_names) > 0:
values = ", ".join(f'"{name}"' for name in ir.constant_names)
sizes = len(ir.constant_names)
d["constant_names_init"] = f"static const char* constant_names_{ir.name}[{sizes}] = {{{values}}};"
d["constant_names"] = f"constant_names_{ir.name}"
else:
d["constant_names_init"] = ""
d["constant_names"] = "NULL"

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():
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 += ["};"]

d["function_spaces_alloc"] = "\n".join(code)
d["function_spaces"] = ""

if len(ir.function_spaces) > 0:
d["function_spaces"] = f"function_spaces_{ir.name}"
values = ", ".join(f"&function_space_{name}_{ir.name_from_uflfile}"
for (name, _) in ir.function_spaces.items())
sizes = len(ir.function_spaces)
d["function_spaces_init"] = f"ufcx_function_space* function_spaces_{ir.name}[{sizes}] = {{{values}}};"
else:
d["function_spaces"] = "NULL"
d["function_spaces_init"] = ""

# Check that no keys are redundant or have been missed
from string import Formatter
fields = [fname for _, fname, _, _ in Formatter().parse(expressions_template.factory) if fname]
assert set(fields) == set(d.keys()), "Mismatch between keys in template and in formatting dict"

# Format implementation code
implementation = expressions_template.factory.format_map(d)

return declaration, implementation
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import logging

import ffcx.codegeneration.basix_custom_element_template as ufcx_basix_custom_finite_element
import ffcx.codegeneration.finite_element_template as ufcx_finite_element
import ffcx.codegeneration.C.basix_custom_element_template as ufcx_basix_custom_finite_element
import ffcx.codegeneration.C.finite_element_template as ufcx_finite_element
import ufl

logger = logging.getLogger("ffcx")
Expand Down Expand Up @@ -63,30 +63,29 @@ def generator(ir, options):
else:
d["basix_cell"] = int(ir.basix_cell)

import ffcx.codegeneration.C.cnodes as L

if len(ir.value_shape) > 0:
d["value_shape"] = f"value_shape_{ir.name}"
d["value_shape_init"] = L.ArrayDecl(
"int", f"value_shape_{ir.name}", values=ir.value_shape, sizes=len(ir.value_shape))
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}"
d["reference_value_shape_init"] = L.ArrayDecl(
"int", f"reference_value_shape_{ir.name}",
values=ir.reference_value_shape, sizes=len(ir.reference_value_shape))
values = ", ".join(str(i) for i in ir.reference_value_shape)
sizes = len(ir.reference_value_shape)
d["reference_value_shape_init"] = f"int reference_value_shape_{ir.name}[{sizes}] = {{{values}}};"
else:
d["reference_value_shape"] = "NULL"
d["reference_value_shape_init"] = ""

if len(ir.sub_elements) > 0:
d["sub_elements"] = f"sub_elements_{ir.name}"
d["sub_elements_init"] = L.ArrayDecl(
"ufcx_finite_element*", f"sub_elements_{ir.name}",
values=[L.AddressOf(L.Symbol(el)) for el in ir.sub_elements], sizes=len(ir.sub_elements))
values = ", ".join(f"&{el}" for el in ir.sub_elements)
sizes = len(ir.sub_elements)
d["sub_elements_init"] = f"ufcx_finite_element* sub_elements_{ir.name}[{sizes}] = {{{values}}};"
else:
d["sub_elements"] = "NULL"
d["sub_elements_init"] = ""
Expand Down Expand Up @@ -126,14 +125,12 @@ def generate_custom_element(name, ir):
d["highest_degree"] = ir.highest_degree
d["discontinuous"] = "true" if ir.discontinuous else "false"
d["interpolation_nderivs"] = ir.interpolation_nderivs

import ffcx.codegeneration.C.cnodes as L

d["value_shape_length"] = len(ir.value_shape)
if len(ir.value_shape) > 0:
d["value_shape"] = f"value_shape_{name}"
d["value_shape_init"] = L.ArrayDecl(
"int", f"value_shape_{name}", values=ir.value_shape, sizes=len(ir.value_shape))
values = ", ".join(str(i) for i in ir.value_shape)
sizes = len(ir.value_shape)
d["value_shape_init"] = f"int value_shape_{name}[{sizes}] = {{{values}}};"
else:
d["value_shape"] = "NULL"
d["value_shape_init"] = ""
Expand Down
Loading

0 comments on commit ff66e31

Please sign in to comment.