370 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
372 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
373 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
376 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
378 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
382 for (
const ufcx_form& ufcx_form : ufcx_forms)
384 if (ufcx_form.rank != (
int)spaces.size())
385 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
386 if (ufcx_form.num_coefficients != (
int)coefficients.size())
388 throw std::runtime_error(
"Mismatch between number of expected and "
389 "provided Form coefficients.");
393 if (ufcx_form.num_constants != (
int)constants.size())
395 throw std::runtime_error(std::format(
396 "Mismatch between number of expected and "
397 "provided Form Constants. Expected {} constants, but got {}.",
398 ufcx_form.num_constants, constants.size()));
400 for (std::size_t c = 0; c < constants.size(); ++c)
402 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
404 throw std::runtime_error(std::format(
405 "Mismatch between expected and actual rank of "
406 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
407 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
409 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
410 ufcx_form.constant_shapes[c]))
412 throw std::runtime_error(
413 std::format(
"Mismatch between expected and actual shape of Form "
414 "Constant for Constant {}.",
421 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
423 for (std::size_t i = 0; i < spaces.size(); ++i)
425 assert(spaces[i]->elements(form_idx));
426 if (
auto element_hash
427 = ufcx_forms[form_idx].get().finite_element_hashes[i];
430 != spaces[i]->elements(form_idx)->basix_element().hash())
432 throw std::runtime_error(
433 "Cannot create form. Elements are different to "
434 "those used to compile the form.");
440 if (!
mesh and !spaces.empty())
441 mesh = spaces.front()->mesh();
443 throw std::runtime_error(
"No mesh could be associated with the Form.");
445 auto topology =
mesh->topology();
447 const int tdim = topology->dim();
452 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
453 std::vector<int> num_integrals_type(3);
454 for (
int i = 0; i < 3; ++i)
455 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
461 mesh->topology_mutable()->create_entities(tdim - 1);
462 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
463 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
468 using kern_t = std::function<void(T*,
const T*,
const T*,
const U*,
469 const int*,
const std::uint8_t*,
void*)>;
472 auto check_geometry_hash
473 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
474 std::size_t cell_idx)
476 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
478 throw std::runtime_error(
479 "Generated integral geometry element does not match mesh geometry: "
480 + std::to_string(integral.coordinate_element_hash) +
", "
481 + std::to_string(geo.cmaps().at(cell_idx).hash()));
486 bool needs_facet_permutations =
false;
488 std::vector<std::int32_t> default_cells;
489 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
490 + integral_offsets[
cell],
491 num_integrals_type[
cell]);
493 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
495 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
496 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
498 const int id = ids[i];
499 ufcx_integral* integral
500 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
502 check_geometry_hash(*integral, form_idx);
505 std::vector<int> active_coeffs;
506 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
508 if (integral->enabled_coefficients[j])
509 active_coeffs.push_back(j);
513 if constexpr (std::is_same_v<T, float>)
514 k = integral->tabulate_tensor_float32;
515#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
516 else if constexpr (std::is_same_v<T, std::complex<float>>)
518 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
519 const scalar_value_t<T>*,
const int*,
520 const unsigned char*,
void*)
>(
521 integral->tabulate_tensor_complex64);
524 else if constexpr (std::is_same_v<T, double>)
525 k = integral->tabulate_tensor_float64;
526#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
527 else if constexpr (std::is_same_v<T, std::complex<double>>)
529 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
530 const scalar_value_t<T>*,
const int*,
531 const unsigned char*,
void*)
>(
532 integral->tabulate_tensor_complex128);
538 throw std::runtime_error(
539 "UFCx kernel function is NULL. Check requested types.");
546 assert(topology->index_maps(tdim).at(form_idx));
547 default_cells.resize(
548 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
549 std::iota(default_cells.begin(), default_cells.end(), 0);
551 {k, default_cells, active_coeffs}});
553 else if (sd != subdomains.end())
556 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
557 [](
auto& a) { return a.first; });
558 if (it != sd->second.end() and it->first ==
id)
562 std::vector<std::int32_t>(it->second.begin(),
568 if (integral->needs_facet_permutations)
569 needs_facet_permutations =
true;
575 std::vector<std::int32_t> default_facets_ext;
577 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
581 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
583 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
586 const int id = ids[i];
587 ufcx_integral* integral
590 check_geometry_hash(*integral, form_idx);
592 std::vector<int> active_coeffs;
593 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
595 if (integral->enabled_coefficients[j])
596 active_coeffs.push_back(j);
600 if constexpr (std::is_same_v<T, float>)
601 k = integral->tabulate_tensor_float32;
602#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
603 else if constexpr (std::is_same_v<T, std::complex<float>>)
605 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
606 const scalar_value_t<T>*,
const int*,
607 const unsigned char*,
void*)
>(
608 integral->tabulate_tensor_complex64);
611 else if constexpr (std::is_same_v<T, double>)
612 k = integral->tabulate_tensor_float64;
613#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
614 else if constexpr (std::is_same_v<T, std::complex<double>>)
616 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
617 const scalar_value_t<T>*,
const int*,
618 const unsigned char*,
void*)
>(
619 integral->tabulate_tensor_complex128);
626 auto f_to_c = topology->connectivity(tdim - 1, tdim);
628 auto c_to_f = topology->connectivity(tdim, tdim - 1);
633 default_facets_ext.reserve(2 * bfacets.size());
634 for (std::int32_t f : bfacets)
637 std::array<std::int32_t, 2> pair
639 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
643 {k, default_facets_ext, active_coeffs}});
645 else if (sd != subdomains.end())
648 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
649 [](
auto& a) { return a.first; });
650 if (it != sd->second.end() and it->first ==
id)
654 std::vector<std::int32_t>(it->second.begin(),
660 if (integral->needs_facet_permutations)
661 needs_facet_permutations =
true;
667 std::vector<std::int32_t> default_facets_int;
669 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
673 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
675 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
678 std::vector<std::int8_t> interprocess_marker;
681 assert(topology->index_map(tdim - 1));
682 const std::vector<std::int32_t>& interprocess_facets
683 = topology->interprocess_facets();
684 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
685 + topology->index_map(tdim - 1)->num_ghosts();
686 interprocess_marker.resize(num_facets, 0);
687 std::ranges::for_each(interprocess_facets,
688 [&interprocess_marker](
auto f)
689 { interprocess_marker[f] = 1; });
694 const int id = ids[i];
695 ufcx_integral* integral
698 check_geometry_hash(*integral, form_idx);
700 std::vector<int> active_coeffs;
701 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
703 if (integral->enabled_coefficients[j])
704 active_coeffs.push_back(j);
708 if constexpr (std::is_same_v<T, float>)
709 k = integral->tabulate_tensor_float32;
710#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
711 else if constexpr (std::is_same_v<T, std::complex<float>>)
713 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
714 const scalar_value_t<T>*,
const int*,
715 const unsigned char*,
void*)
>(
716 integral->tabulate_tensor_complex64);
719 else if constexpr (std::is_same_v<T, double>)
720 k = integral->tabulate_tensor_float64;
721#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
722 else if constexpr (std::is_same_v<T, std::complex<double>>)
724 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
725 const scalar_value_t<T>*,
const int*,
726 const unsigned char*,
void*)
>(
727 integral->tabulate_tensor_complex128);
733 auto f_to_c = topology->connectivity(tdim - 1, tdim);
735 auto c_to_f = topology->connectivity(tdim, tdim - 1);
740 assert(topology->index_map(tdim - 1));
741 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
742 default_facets_int.reserve(4 * num_facets);
743 for (std::int32_t f = 0; f < num_facets; ++f)
745 if (f_to_c->num_links(f) == 2)
747 std::array<std::int32_t, 4> pairs
749 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
752 else if (interprocess_marker[f])
754 throw std::runtime_error(
755 "Cannot compute interior facet integral over interprocess "
756 "facet. Please use ghost mode shared facet when creating the "
761 {k, default_facets_int, active_coeffs}});
763 else if (sd != subdomains.end())
765 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
766 [](
auto& a) { return a.first; });
767 if (it != sd->second.end() and it->first ==
id)
771 std::vector<std::int32_t>(it->second.begin(),
777 if (integral->needs_facet_permutations)
778 needs_facet_permutations =
true;
783 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
784 needs_facet_permutations, entity_maps);