86 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
88 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
89 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
92 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
94 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
98 for (std::size_t c = 0; c < coefficients.size(); ++c)
100 if (!coefficients[c])
102 throw std::invalid_argument(
103 std::format(
"Cannot create form. Coefficient {} is null.", c));
107 for (std::size_t c = 0; c < constants.size(); ++c)
111 throw std::invalid_argument(
112 std::format(
"Cannot create form. Constant {} is null.", c));
116 for (
const ufcx_form& ufcx_form : ufcx_forms)
118 if (ufcx_form.rank != (
int)spaces.size())
119 throw std::invalid_argument(
"Wrong number of argument spaces for Form.");
120 if (ufcx_form.num_coefficients != (
int)coefficients.size())
122 throw std::invalid_argument(
"Mismatch between number of expected and "
123 "provided Form coefficients.");
127 if (ufcx_form.num_constants != (
int)constants.size())
129 throw std::invalid_argument(std::format(
130 "Mismatch between number of expected and "
131 "provided Form Constants. Expected {} constants, but got {}.",
132 ufcx_form.num_constants, constants.size()));
134 for (std::size_t c = 0; c < constants.size(); ++c)
136 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
138 throw std::invalid_argument(std::format(
139 "Mismatch between expected and actual rank of "
140 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
141 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
143 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
144 ufcx_form.constant_shapes[c]))
146 throw std::invalid_argument(
147 std::format(
"Mismatch between expected and actual shape of Form "
148 "Constant for Constant {}.",
155 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
157 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
158 for (std::size_t i = 0; i < spaces.size(); ++i)
160 assert(spaces[i]->elements(form_idx));
161 if (std::uint64_t element_hash = ufcx_form.finite_element_hashes[i];
164 != spaces[i]->elements(form_idx)->basix_element().hash())
166 throw std::invalid_argument(
167 "Cannot create form. Elements are different to "
168 "those used to compile the form.");
172 for (std::size_t c = 0; c < coefficients.size(); ++c)
174 std::uint64_t element_hash
175 = ufcx_form.finite_element_hashes[ufcx_form.rank + c];
176 if (element_hash != 0
184 throw std::invalid_argument(std::format(
185 "Cannot create form. Coefficient {} element differs from the "
186 "element used to compile the form.",
193 if (!
mesh and !spaces.empty())
194 mesh = spaces.front()->mesh();
196 throw std::invalid_argument(
"No mesh could be associated with the Form.");
198 auto topology =
mesh->topology();
200 const int tdim = topology->dim();
205 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
206 std::array<int, 5> num_integrals_type;
207 for (std::size_t i = 0; i < num_integrals_type.size(); ++i)
208 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
211 if (num_integrals_type[
vertex] > 0)
213 mesh->topology_mutable()->create_connectivity(0, tdim);
214 mesh->topology_mutable()->create_connectivity(tdim, 0);
222 mesh->topology_mutable()->create_entities(tdim - 1);
223 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
224 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
228 if (num_integrals_type[
ridge] > 0)
230 mesh->topology_mutable()->create_entities(tdim - 2);
231 mesh->topology_mutable()->create_connectivity(tdim - 2, tdim);
232 mesh->topology_mutable()->create_connectivity(tdim, tdim - 2);
239 auto check_geometry_hash
240 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
241 std::size_t cell_idx)
243 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
245 throw std::invalid_argument(std::format(
246 "Generated integral geometry element does not match mesh geometry: "
248 integral.coordinate_element_hash, geo.cmaps().at(cell_idx).hash()));
253 bool needs_facet_permutations =
false;
255 std::vector<std::int32_t> default_cells;
256 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
257 + integral_offsets[
cell],
258 num_integrals_type[
cell]);
260 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
262 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
263 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
265 const int id = ids[i];
266 ufcx_integral* integral
267 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
269 check_geometry_hash(*integral, form_idx);
272 std::vector<int> active_coeffs;
273 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
275 if (integral->enabled_coefficients[j])
276 active_coeffs.push_back(j);
279 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
282 throw std::invalid_argument(
283 "UFCx kernel function is NULL. Check requested types.");
290 assert(topology->index_maps(tdim).at(form_idx));
291 default_cells.resize(
292 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
293 std::iota(default_cells.begin(), default_cells.end(), 0);
295 {k, default_cells, active_coeffs}});
297 else if (sd != subdomains.end())
300 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
301 [](
auto& a) { return a.first; });
302 if (it != sd->second.end() and it->first ==
id)
306 std::vector<std::int32_t>(it->second.begin(),
312 if (integral->needs_facet_permutations)
313 needs_facet_permutations =
true;
320 std::vector<std::int32_t> default_facets_int;
321 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
325 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
327 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
330 std::vector<std::int8_t> interprocess_marker;
333 assert(topology->index_map(tdim - 1));
334 const std::vector<std::int32_t>& interprocess_facets
335 = topology->interprocess_facets();
336 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
337 + topology->index_map(tdim - 1)->num_ghosts();
338 interprocess_marker.resize(num_facets, 0);
339 std::ranges::for_each(interprocess_facets,
340 [&interprocess_marker](
auto f)
341 { interprocess_marker[f] = 1; });
346 const int id = ids[i];
347 ufcx_integral* integral
350 check_geometry_hash(*integral, form_idx);
352 std::vector<int> active_coeffs;
353 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
355 if (integral->enabled_coefficients[j])
356 active_coeffs.push_back(j);
359 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
363 auto f_to_c = topology->connectivity(tdim - 1, tdim);
365 auto c_to_f = topology->connectivity(tdim, tdim - 1);
370 assert(topology->index_map(tdim - 1));
371 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
372 default_facets_int.reserve(4 * num_facets);
373 for (std::int32_t f = 0; f < num_facets; ++f)
375 if (f_to_c->num_links(f) == 2)
377 std::array<std::int32_t, 4> pairs
378 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
379 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
382 else if (interprocess_marker[f])
384 throw std::runtime_error(
385 "Cannot compute interior facet integral over interprocess "
386 "facet. Please use ghost mode shared facet when creating the "
391 {k, default_facets_int, active_coeffs}});
393 else if (sd != subdomains.end())
395 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
396 [](
auto& a) { return a.first; });
397 if (it != sd->second.end() and it->first ==
id)
401 std::vector<std::int32_t>(it->second.begin(),
407 if (integral->needs_facet_permutations)
408 needs_facet_permutations =
true;
420 const std::function<std::vector<std::int32_t>(
const mesh::Topology&,
422 get_default_integration_entities
433 std::int32_t num_entities = topology.
index_map(dim)->size_local();
434 std::vector<std::int32_t> entities(num_entities);
435 std::iota(entities.begin(), entities.end(), 0);
440 std::vector<std::int32_t> default_entities_ext;
442 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
443 + integral_offsets[(std::int8_t)itg_type],
444 num_integrals_type[(std::int8_t)itg_type]);
445 auto sd = subdomains.find(itg_type);
446 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
448 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
449 for (
int i = 0; i < num_integrals_type[(std::int8_t)itg_type]; ++i)
451 const int id = ids[i];
452 ufcx_integral* integral
453 = ufcx_form.form_integrals[integral_offsets[(std::int8_t)itg_type]
456 check_geometry_hash(*integral, form_idx);
458 std::vector<int> active_coeffs;
459 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
461 if (integral->enabled_coefficients[j])
462 active_coeffs.push_back(j);
465 impl::kernel_t<T, U> k = impl::extract_kernel<T, U>(integral);
474 std::vector default_entities
475 = get_default_integration_entities(*topology, itg_type);
477 default_entities_ext.reserve(2 * default_entities.size());
478 for (std::int32_t e : default_entities)
481 std::array<std::int32_t, 2> pair = impl::get_cell_entity_pairs<1>(
482 e, e_to_c->links(e), *c_to_e);
483 default_entities_ext.insert(default_entities_ext.end(),
484 pair.begin(), pair.end());
486 integrals.insert({{itg_type, i, form_idx},
487 {k, default_entities_ext, active_coeffs}});
489 else if (sd != subdomains.end())
492 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
493 [](
auto& a) { return a.first; });
494 if (it != sd->second.end() and it->first ==
id)
496 integrals.insert({{itg_type, i, form_idx},
498 std::vector<std::int32_t>(it->second.begin(),
504 if (integral->needs_facet_permutations)
505 needs_facet_permutations =
true;
511 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
512 needs_facet_permutations, entity_maps);