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

FEniCS / ffcx / 15758403795

19 Jun 2025 12:56PM UTC coverage: 82.081% (-0.04%) from 82.12%
15758403795

Pull #767

github

garth-wells
Simplify
Pull Request #767: Add rank and shape of constants to UFCx

25 of 26 new or added lines in 3 files covered. (96.15%)

12 existing lines in 3 files now uncovered.

3605 of 4392 relevant lines covered (82.08%)

0.82 hits per line

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

95.1
/ffcx/codegeneration/C/form.py
1
# Copyright (C) 2009-2017 Anders Logg and Martin Sandve Alnæs
2
#
3
# This file is part of FFCx.(https://www.fenicsproject.org)
4
#
5
# SPDX-License-Identifier:    LGPL-3.0-or-later
6
#
7
# Modified by Chris Richardson and Jørgen S. Dokken 2023
8
#
9
# Note: Most of the code in this file is a direct translation from the
10
# old implementation in FFC
11
"""Generate UFC code for a form."""
12

13
from __future__ import annotations
1✔
14

15
import logging
1✔
16
import typing
1✔
17

18
import numpy as np
1✔
19

20
from ffcx.codegeneration.C import form_template
1✔
21
from ffcx.ir.representation import FormIR
1✔
22

23
logger = logging.getLogger("ffcx")
1✔
24

25

26
def generator(ir: FormIR, options):
1✔
27
    """Generate UFCx code for a form."""
28
    logger.info("Generating code for form:")
1✔
29
    logger.info(f"--- rank: {ir.rank}")
1✔
30
    logger.info(f"--- name: {ir.name}")
1✔
31

32
    d: dict[str, typing.Union[int, str]] = {}
1✔
33
    d["factory_name"] = ir.name
1✔
34
    d["name_from_uflfile"] = ir.name_from_uflfile
1✔
35
    d["signature"] = f'"{ir.signature}"'
1✔
36
    d["rank"] = ir.rank
1✔
37
    d["num_coefficients"] = ir.num_coefficients
1✔
38

39
    if len(ir.original_coefficient_positions) > 0:
1✔
40
        values = ", ".join(str(i) for i in ir.original_coefficient_positions)
1✔
41
        sizes = len(ir.original_coefficient_positions)
1✔
42

43
        d["original_coefficient_position_init"] = (
1✔
44
            f"int original_coefficient_position_{ir.name}[{sizes}] = {{{values}}};"
45
        )
46
        d["original_coefficient_positions"] = f"original_coefficient_position_{ir.name}"
1✔
47
    else:
48
        d["original_coefficient_position_init"] = ""
1✔
49
        d["original_coefficient_positions"] = "NULL"
1✔
50

51
    if len(ir.coefficient_names) > 0:
1✔
52
        values = ", ".join(f'"{name}"' for name in ir.coefficient_names)
1✔
53
        sizes = len(ir.coefficient_names)
1✔
54
        d["coefficient_names_init"] = (
1✔
55
            f"static const char* coefficient_names_{ir.name}[{sizes}] = {{{values}}};"
56
        )
57
        d["coefficient_names"] = f"coefficient_names_{ir.name}"
1✔
58
    else:
59
        d["coefficient_names_init"] = ""
1✔
60
        d["coefficient_names"] = "NULL"
1✔
61

62
    d["num_constants"] = ir.num_constants
1✔
63
    if ir.num_constants > 0:
1✔
64
        d["constant_ranks_init"] = (
1✔
65
            f"static const int constant_ranks_{ir.name}[{ir.num_constants}] = "
66
            f"{str(ir.constant_ranks).replace('[', '{').replace(']', '}')};"
67
        )
68
        d["constant_ranks"] = f"constant_ranks_{ir.name}"
1✔
69

70
        shapes = [
1✔
71
            f"static const int constant_shapes_{ir.name}_{i}[{len(shape)}] = "
72
            f"{str(shape).replace('(', '{').replace(')', '}')};"
73
            for i, shape in enumerate(ir.constant_shapes)
74
            if len(shape) > 0
75
        ]
76
        names = [f"constant_shapes_{ir.name}_{i}" for i in range(ir.num_constants)]
1✔
77
        shapes1 = f"static const int* constant_shapes_{ir.name}[{ir.num_constants}] = " + "{"
1✔
78
        for rank, name in zip(ir.constant_ranks, names):
1✔
79
            if rank > 0:
1✔
80
                shapes1 += f"{name},\n"
1✔
81
            else:
NEW
82
                shapes1 += "NULL,\n"
×
83
        shapes1 += "};"
1✔
84
        shapes.append(shapes1)
1✔
85

86
        d["constant_shapes_init"] = "\n".join(shapes)
1✔
87
        d["constant_shapes"] = f"constant_shapes_{ir.name}"
1✔
88
    else:
89
        d["constant_ranks_init"] = ""
1✔
90
        d["constant_ranks"] = "NULL"
1✔
91
        d["constant_shapes_init"] = ""
1✔
92
        d["constant_shapes"] = "NULL"
1✔
93

94
    if len(ir.constant_names) > 0:
1✔
95
        values = ", ".join(f'"{name}"' for name in ir.constant_names)
1✔
96
        sizes = len(ir.constant_names)
1✔
97
        d["constant_names_init"] = (
1✔
98
            f"static const char* constant_names_{ir.name}[{sizes}] = {{{values}}};"
99
        )
100
        d["constant_names"] = f"constant_names_{ir.name}"
1✔
101
    else:
102
        d["constant_names_init"] = ""
1✔
103
        d["constant_names"] = "NULL"
1✔
104

105
    if len(ir.finite_element_hashes) > 0:
1✔
106
        d["finite_element_hashes"] = f"finite_element_hashes_{ir.name}"
1✔
107
        values = ", ".join(
1✔
108
            f"UINT64_C({0 if el is None else el})" for el in ir.finite_element_hashes
109
        )
110
        sizes = len(ir.finite_element_hashes)
1✔
111
        d["finite_element_hashes_init"] = (
1✔
112
            f"uint64_t finite_element_hashes_{ir.name}[{sizes}] = {{{values}}};"
113
        )
114
    else:
115
        d["finite_element_hashes"] = "NULL"
1✔
116
        d["finite_element_hashes_init"] = ""
1✔
117

118
    integrals = []
1✔
119
    integral_ids = []
1✔
120
    integral_offsets = [0]
1✔
121
    integral_domains = []
1✔
122
    # Note: the order of this list is defined by the enum ufcx_integral_type in ufcx.h
123
    for itg_type in ("cell", "exterior_facet", "interior_facet"):
1✔
124
        unsorted_integrals = []
1✔
125
        unsorted_ids = []
1✔
126
        unsorted_domains = []
1✔
127
        for name, domains, id in zip(
1✔
128
            ir.integral_names[itg_type],
129
            ir.integral_domains[itg_type],
130
            ir.subdomain_ids[itg_type],
131
        ):
132
            unsorted_integrals += [f"&{name}"]
1✔
133
            unsorted_ids += [id]
1✔
134
            unsorted_domains += [domains]
1✔
135

136
        id_sort = np.argsort(unsorted_ids)
1✔
137
        integrals += [unsorted_integrals[i] for i in id_sort]
1✔
138
        integral_ids += [unsorted_ids[i] for i in id_sort]
1✔
139
        integral_domains += [unsorted_domains[i] for i in id_sort]
1✔
140

141
        integral_offsets.append(sum(len(d) for d in integral_domains))
1✔
142

143
    if len(integrals) > 0:
1✔
144
        sizes = sum(len(domains) for domains in integral_domains)
1✔
145
        values = ", ".join(
1✔
146
            [
147
                f"{i}_{domain.name}"
148
                for i, domains in zip(integrals, integral_domains)
149
                for domain in domains
150
            ]
151
        )
152
        d["form_integrals_init"] = (
1✔
153
            f"static ufcx_integral* form_integrals_{ir.name}[{sizes}] = {{{values}}};"
154
        )
155
        d["form_integrals"] = f"form_integrals_{ir.name}"
1✔
156
        values = ", ".join(
1✔
157
            f"{i}" for i, domains in zip(integral_ids, integral_domains) for _ in domains
158
        )
159
        d["form_integral_ids_init"] = f"int form_integral_ids_{ir.name}[{sizes}] = {{{values}}};"
1✔
160
        d["form_integral_ids"] = f"form_integral_ids_{ir.name}"
1✔
161
    else:
162
        d["form_integrals_init"] = ""
×
163
        d["form_integrals"] = "NULL"
×
164
        d["form_integral_ids_init"] = ""
×
165
        d["form_integral_ids"] = "NULL"
×
166

167
    sizes = len(integral_offsets)
1✔
168
    values = ", ".join(str(i) for i in integral_offsets)
1✔
169
    d["form_integral_offsets_init"] = (
1✔
170
        f"int form_integral_offsets_{ir.name}[{sizes}] = {{{values}}};"
171
    )
172

173
    # Check that no keys are redundant or have been missed
174
    from string import Formatter
1✔
175

176
    fields = [fname for _, fname, _, _ in Formatter().parse(form_template.factory) if fname]
1✔
177
    assert set(fields) == set(d.keys()), "Mismatch between keys in template and in formatting dict"
1✔
178

179
    # Format implementation code
180
    implementation = form_template.factory.format_map(d)
1✔
181

182
    # Format declaration
183
    declaration = form_template.declaration.format(
1✔
184
        factory_name=d["factory_name"], name_from_uflfile=d["name_from_uflfile"]
185
    )
186

187
    return declaration, implementation
1✔
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