• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FEniCS / ffcx / 20002766017

07 Dec 2025 10:19AM UTC coverage: 79.933% (-4.5%) from 84.457%
20002766017

Pull #803

github

schnellerhase
Move macro definition to file template
Pull Request #803: Add `C++` backend

0 of 272 new or added lines in 10 files covered. (0.0%)

4059 of 5078 relevant lines covered (79.93%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/ffcx/codegeneration/cpp/expressions.py
1
# Copyright (C) 2019 Michal Habera
2
#
3
# This file is part of FFCx.(https://www.fenicsproject.org)
4
#
5
# SPDX-License-Identifier:    LGPL-3.0-or-later
6
"""Generate code for an expression."""
7

NEW
8
import logging
×
NEW
9
import string
×
10

NEW
11
import numpy as np
×
12

NEW
13
from ffcx.codegeneration.backend import FFCXBackend
×
NEW
14
from ffcx.codegeneration.C import expressions_template
×
NEW
15
from ffcx.codegeneration.C.implementation import Formatter
×
NEW
16
from ffcx.codegeneration.expression_generator import ExpressionGenerator
×
NEW
17
from ffcx.codegeneration.utils import dtype_to_c_type, dtype_to_scalar_dtype
×
18

NEW
19
logger = logging.getLogger("ffcx")
×
20

21

NEW
22
def generator(ir, options):
×
23
    """Generate UFC code for an expression."""
NEW
24
    logger.info("Generating code for expression:")
×
NEW
25
    assert len(ir.expression.integrand) == 1, "Expressions only support single quadrature rule"
×
NEW
26
    points = next(iter(ir.expression.integrand))[1].points
×
NEW
27
    logger.info(f"--- points: {points}")
×
NEW
28
    factory_name = ir.expression.name
×
NEW
29
    logger.info(f"--- name: {factory_name}")
×
30

31
    # Format declaration
NEW
32
    declaration = expressions_template.declaration.format(
×
33
        factory_name=factory_name, name_from_uflfile=ir.name_from_uflfile
34
    )
35

NEW
36
    backend = FFCXBackend(ir, options)
×
NEW
37
    eg = ExpressionGenerator(ir, backend)
×
38

NEW
39
    d = {}
×
NEW
40
    d["name_from_uflfile"] = ir.name_from_uflfile
×
NEW
41
    d["factory_name"] = factory_name
×
42

NEW
43
    parts = eg.generate()
×
44

NEW
45
    CF = Formatter(options["scalar_type"])
×
NEW
46
    d["tabulate_expression"] = CF.format(parts)
×
47

NEW
48
    if len(ir.original_coefficient_positions) > 0:
×
NEW
49
        d["original_coefficient_positions"] = f"original_coefficient_positions_{factory_name}"
×
NEW
50
        sizes = len(ir.original_coefficient_positions)
×
NEW
51
        values = ", ".join(str(i) for i in ir.original_coefficient_positions)
×
NEW
52
        d["original_coefficient_positions_init"] = (
×
53
            f"static int original_coefficient_positions_{factory_name}[{sizes}] = {{{values}}};"
54
        )
55

56
    else:
NEW
57
        d["original_coefficient_positions"] = "NULL"
×
NEW
58
        d["original_coefficient_positions_init"] = ""
×
59

NEW
60
    values = ", ".join(str(p) for p in points.flatten())
×
NEW
61
    sizes = points.size
×
NEW
62
    d["points_init"] = f"static double points_{factory_name}[{sizes}] = {{{values}}};"
×
NEW
63
    d["points"] = f"points_{factory_name}"
×
64

NEW
65
    if len(ir.expression.shape) > 0:
×
NEW
66
        values = ", ".join(str(i) for i in ir.expression.shape)
×
NEW
67
        sizes = len(ir.expression.shape)
×
NEW
68
        d["value_shape_init"] = f"static int value_shape_{factory_name}[{sizes}] = {{{values}}};"
×
NEW
69
        d["value_shape"] = f"value_shape_{factory_name}"
×
70
    else:
NEW
71
        d["value_shape_init"] = ""
×
NEW
72
        d["value_shape"] = "NULL"
×
73

NEW
74
    d["num_components"] = len(ir.expression.shape)
×
NEW
75
    d["num_coefficients"] = len(ir.expression.coefficient_numbering)
×
NEW
76
    d["num_constants"] = len(ir.constant_names)
×
NEW
77
    d["num_points"] = points.shape[0]
×
NEW
78
    d["entity_dimension"] = points.shape[1]
×
NEW
79
    d["scalar_type"] = dtype_to_c_type(options["scalar_type"])
×
NEW
80
    d["geom_type"] = dtype_to_c_type(dtype_to_scalar_dtype(options["scalar_type"]))
×
NEW
81
    d["np_scalar_type"] = np.dtype(options["scalar_type"]).name
×
82

NEW
83
    d["rank"] = len(ir.expression.tensor_shape)
×
84

NEW
85
    if len(ir.coefficient_names) > 0:
×
NEW
86
        values = ", ".join(f'"{name}"' for name in ir.coefficient_names)
×
NEW
87
        sizes = len(ir.coefficient_names)
×
NEW
88
        d["coefficient_names_init"] = (
×
89
            f"static const char* coefficient_names_{factory_name}[{sizes}] = {{{values}}};"
90
        )
91

NEW
92
        d["coefficient_names"] = f"coefficient_names_{factory_name}"
×
93
    else:
NEW
94
        d["coefficient_names_init"] = ""
×
NEW
95
        d["coefficient_names"] = "NULL"
×
96

NEW
97
    if len(ir.constant_names) > 0:
×
NEW
98
        values = ", ".join(f'"{name}"' for name in ir.constant_names)
×
NEW
99
        sizes = len(ir.constant_names)
×
NEW
100
        d["constant_names_init"] = (
×
101
            f"static const char* constant_names_{factory_name}[{sizes}] = {{{values}}};"
102
        )
NEW
103
        d["constant_names"] = f"constant_names_{factory_name}"
×
104
    else:
NEW
105
        d["constant_names_init"] = ""
×
NEW
106
        d["constant_names"] = "NULL"
×
107

108
    # TODO: make cpp
NEW
109
    d["coordinate_element_hash"] = f"UINT64_C({ir.expression.coordinate_element_hash})"
×
110

111
    # FIXME: Should be handled differently, revise how
112
    # ufcx_function_space is generated (also for ufcx_form)
113
    # for name, (element, dofmap, cmap_family, cmap_degree) in ir.function_spaces.items():
114
    #     code += [f"static ufcx_function_space function_space_{name}_{ir.name_from_uflfile} ="]
115
    #     code += ["{"]
116
    #     code += [f".finite_element = &{element},"]
117
    #     code += [f".dofmap = &{dofmap},"]
118
    #     code += [f'.geometry_family = "{cmap_family}",']
119
    #     code += [f".geometry_degree = {cmap_degree}"]
120
    #     code += ["};"]
121

122
    # d["function_spaces_alloc"] = "\n".join(code)
123
    # d["function_spaces"] = ""
124

125
    # if len(ir.function_spaces) > 0:
126
    #     d["function_spaces"] = f"function_spaces_{ir.name}"
127
    #     fs_list = ", ".join(
128
    #         f"&function_space_{name}_{ir.name_from_uflfile}"
129
    #         for (name, _) in ir.function_spaces.items()
130
    #     )
131
    #     n = len(ir.function_spaces.items())
132
    #     d["function_spaces_init"] = (
133
    #         f"ufcx_function_space* function_spaces_{ir.name}[{n}] = {{{fs_list}}};"
134
    #     )
135
    # else:
136
    #     d["function_spaces"] = "NULL"
137
    #     d["function_spaces_init"] = ""
138

139
    # Check that no keys are redundant or have been missed
NEW
140
    fields = [
×
141
        fname for _, fname, _, _ in string.Formatter().parse(expressions_template.factory) if fname
142
    ]
NEW
143
    assert set(fields) == set(d.keys()), "Mismatch between keys in template and in formatting dict"
×
144

145
    # Format implementation code
NEW
146
    implementation = expressions_template.factory.format_map(d)
×
147

NEW
148
    return declaration, implementation
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc