77 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
79 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
80 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
83 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
85 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
89 for (
const ufcx_form& ufcx_form : ufcx_forms)
91 if (ufcx_form.rank != (
int)spaces.size())
92 throw std::invalid_argument(
"Wrong number of argument spaces for Form.");
93 if (ufcx_form.num_coefficients != (
int)coefficients.size())
95 throw std::invalid_argument(
"Mismatch between number of expected and "
96 "provided Form coefficients.");
100 if (ufcx_form.num_constants != (
int)constants.size())
102 throw std::invalid_argument(std::format(
103 "Mismatch between number of expected and "
104 "provided Form Constants. Expected {} constants, but got {}.",
105 ufcx_form.num_constants, constants.size()));
107 for (std::size_t c = 0; c < constants.size(); ++c)
109 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
111 throw std::invalid_argument(std::format(
112 "Mismatch between expected and actual rank of "
113 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
114 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
116 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
117 ufcx_form.constant_shapes[c]))
119 throw std::invalid_argument(
120 std::format(
"Mismatch between expected and actual shape of Form "
121 "Constant for Constant {}.",
128 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
130 for (std::size_t i = 0; i < spaces.size(); ++i)
132 assert(spaces[i]->elements(form_idx));
133 if (
auto element_hash
134 = ufcx_forms[form_idx].get().finite_element_hashes[i];
137 != spaces[i]->elements(form_idx)->basix_element().hash())
139 throw std::invalid_argument(
140 "Cannot create form. Elements are different to "
141 "those used to compile the form.");
147 if (!
mesh and !spaces.empty())
148 mesh = spaces.front()->mesh();
150 throw std::invalid_argument(
"No mesh could be associated with the Form.");
152 auto topology =
mesh->topology();
154 const int tdim = topology->dim();
159 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
160 std::array<int, 5> num_integrals_type;
161 for (std::size_t i = 0; i < num_integrals_type.size(); ++i)
162 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
165 if (num_integrals_type[
vertex] > 0)
167 mesh->topology_mutable()->create_connectivity(0, tdim);
168 mesh->topology_mutable()->create_connectivity(tdim, 0);
176 mesh->topology_mutable()->create_entities(tdim - 1);
177 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
178 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
182 if (num_integrals_type[
ridge] > 0)
184 mesh->topology_mutable()->create_entities(tdim - 2);
185 mesh->topology_mutable()->create_connectivity(tdim - 2, tdim);
186 mesh->topology_mutable()->create_connectivity(tdim, tdim - 2);
193 auto check_geometry_hash
194 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
195 std::size_t cell_idx)
197 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
199 throw std::runtime_error(std::format(
200 "Generated integral geometry element does not match mesh geometry: "
202 integral.coordinate_element_hash, geo.cmaps().at(cell_idx).hash()));
207 bool needs_facet_permutations =
false;
209 std::vector<std::int32_t> default_cells;
210 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
211 + integral_offsets[
cell],
212 num_integrals_type[
cell]);
214 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
216 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
217 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
219 const int id = ids[i];
220 ufcx_integral* integral
221 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
223 check_geometry_hash(*integral, form_idx);
226 std::vector<int> active_coeffs;
227 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
229 if (integral->enabled_coefficients[j])
230 active_coeffs.push_back(j);
233 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
236 throw std::invalid_argument(
237 "UFCx kernel function is NULL. Check requested types.");
244 assert(topology->index_maps(tdim).at(form_idx));
245 default_cells.resize(
246 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
247 std::iota(default_cells.begin(), default_cells.end(), 0);
249 {k, default_cells, active_coeffs}});
251 else if (sd != subdomains.end())
254 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
255 [](
auto& a) { return a.first; });
256 if (it != sd->second.end() and it->first ==
id)
260 std::vector<std::int32_t>(it->second.begin(),
266 if (integral->needs_facet_permutations)
267 needs_facet_permutations =
true;
274 std::vector<std::int32_t> default_facets_int;
275 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
279 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
281 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
284 std::vector<std::int8_t> interprocess_marker;
287 assert(topology->index_map(tdim - 1));
288 const std::vector<std::int32_t>& interprocess_facets
289 = topology->interprocess_facets();
290 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
291 + topology->index_map(tdim - 1)->num_ghosts();
292 interprocess_marker.resize(num_facets, 0);
293 std::ranges::for_each(interprocess_facets,
294 [&interprocess_marker](
auto f)
295 { interprocess_marker[f] = 1; });
300 const int id = ids[i];
301 ufcx_integral* integral
304 check_geometry_hash(*integral, form_idx);
306 std::vector<int> active_coeffs;
307 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
309 if (integral->enabled_coefficients[j])
310 active_coeffs.push_back(j);
313 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
317 auto f_to_c = topology->connectivity(tdim - 1, tdim);
319 auto c_to_f = topology->connectivity(tdim, tdim - 1);
324 assert(topology->index_map(tdim - 1));
325 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
326 default_facets_int.reserve(4 * num_facets);
327 for (std::int32_t f = 0; f < num_facets; ++f)
329 if (f_to_c->num_links(f) == 2)
331 std::array<std::int32_t, 4> pairs
332 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
333 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
336 else if (interprocess_marker[f])
338 throw std::runtime_error(
339 "Cannot compute interior facet integral over interprocess "
340 "facet. Please use ghost mode shared facet when creating the "
345 {k, default_facets_int, active_coeffs}});
347 else if (sd != subdomains.end())
349 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
350 [](
auto& a) { return a.first; });
351 if (it != sd->second.end() and it->first ==
id)
355 std::vector<std::int32_t>(it->second.begin(),
361 if (integral->needs_facet_permutations)
362 needs_facet_permutations =
true;
374 const std::function<std::vector<std::int32_t>(
const mesh::Topology&,
376 get_default_integration_entities
387 std::int32_t num_entities = topology.
index_map(dim)->size_local();
388 std::vector<std::int32_t> entities(num_entities);
389 std::iota(entities.begin(), entities.end(), 0);
394 std::vector<std::int32_t> default_entities_ext;
396 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
397 + integral_offsets[(std::int8_t)itg_type],
398 num_integrals_type[(std::int8_t)itg_type]);
399 auto sd = subdomains.find(itg_type);
400 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
402 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
403 for (
int i = 0; i < num_integrals_type[(std::int8_t)itg_type]; ++i)
405 const int id = ids[i];
406 ufcx_integral* integral
407 = ufcx_form.form_integrals[integral_offsets[(std::int8_t)itg_type]
410 check_geometry_hash(*integral, form_idx);
412 std::vector<int> active_coeffs;
413 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
415 if (integral->enabled_coefficients[j])
416 active_coeffs.push_back(j);
419 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
428 std::vector default_entities
429 = get_default_integration_entities(*topology, itg_type);
431 default_entities_ext.reserve(2 * default_entities.size());
432 for (std::int32_t e : default_entities)
435 std::array<std::int32_t, 2> pair = impl::get_cell_entity_pairs<1>(
436 e, e_to_c->links(e), *c_to_e);
437 default_entities_ext.insert(default_entities_ext.end(),
438 pair.begin(), pair.end());
440 integrals.insert({{itg_type, i, form_idx},
441 {k, default_entities_ext, active_coeffs}});
443 else if (sd != subdomains.end())
446 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
447 [](
auto& a) { return a.first; });
448 if (it != sd->second.end() and it->first ==
id)
450 integrals.insert({{itg_type, i, form_idx},
452 std::vector<std::int32_t>(it->second.begin(),
458 if (integral->needs_facet_permutations)
459 needs_facet_permutations =
true;
465 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
466 needs_facet_permutations, entity_maps);