366 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
368 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
369 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
372 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
375 std::span<const std::int32_t>>& entity_maps,
378 for (
const ufcx_form& ufcx_form : ufcx_forms)
380 if (ufcx_form.rank != (
int)spaces.size())
381 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
382 if (ufcx_form.num_coefficients != (
int)coefficients.size())
384 throw std::runtime_error(
"Mismatch between number of expected and "
385 "provided Form coefficients.");
389 if (ufcx_form.num_constants != (
int)constants.size())
391 throw std::runtime_error(std::format(
392 "Mismatch between number of expected and "
393 "provided Form Constants. Expected {} constants, but got {}.",
394 ufcx_form.num_constants, constants.size()));
396 for (std::size_t c = 0; c < constants.size(); ++c)
398 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
400 throw std::runtime_error(std::format(
401 "Mismatch between expected and actual rank of "
402 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
403 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
405 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
406 ufcx_form.constant_shapes[c]))
408 throw std::runtime_error(
409 std::format(
"Mismatch between expected and actual shape of Form "
410 "Constant for Constant {}.",
417 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
419 for (std::size_t i = 0; i < spaces.size(); ++i)
421 assert(spaces[i]->elements(form_idx));
422 if (
auto element_hash
423 = ufcx_forms[form_idx].get().finite_element_hashes[i];
426 != spaces[i]->elements(form_idx)->basix_element().hash())
428 throw std::runtime_error(
429 "Cannot create form. Elements are different to "
430 "those used to compile the form.");
436 if (!
mesh and !spaces.empty())
437 mesh = spaces.front()->mesh();
439 throw std::runtime_error(
"No mesh could be associated with the Form.");
440 for (
auto& V : spaces)
442 if (
mesh != V->mesh() and entity_maps.find(V->mesh()) == entity_maps.end())
444 throw std::runtime_error(
445 "Incompatible mesh. entity_maps must be provided.");
449 auto topology =
mesh->topology();
451 const int tdim = topology->dim();
456 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
457 std::vector<int> num_integrals_type(3);
458 for (
int i = 0; i < 3; ++i)
459 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
465 mesh->topology_mutable()->create_entities(tdim - 1);
466 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
467 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
472 using kern_t = std::function<void(T*,
const T*,
const T*,
const U*,
473 const int*,
const std::uint8_t*,
void*)>;
476 auto check_geometry_hash
477 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
478 std::size_t cell_idx)
480 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
482 throw std::runtime_error(
483 "Generated integral geometry element does not match mesh geometry: "
484 + std::to_string(integral.coordinate_element_hash) +
", "
485 + std::to_string(geo.cmaps().at(cell_idx).hash()));
490 bool needs_facet_permutations =
false;
492 std::vector<std::int32_t> default_cells;
493 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
494 + integral_offsets[
cell],
495 num_integrals_type[
cell]);
497 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
499 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
500 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
502 const int id = ids[i];
503 ufcx_integral* integral
504 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
506 check_geometry_hash(*integral, form_idx);
509 std::vector<int> active_coeffs;
510 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
512 if (integral->enabled_coefficients[j])
513 active_coeffs.push_back(j);
517 if constexpr (std::is_same_v<T, float>)
518 k = integral->tabulate_tensor_float32;
519#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
520 else if constexpr (std::is_same_v<T, std::complex<float>>)
522 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
523 const scalar_value_t<T>*,
const int*,
524 const unsigned char*,
void*)
>(
525 integral->tabulate_tensor_complex64);
528 else if constexpr (std::is_same_v<T, double>)
529 k = integral->tabulate_tensor_float64;
530#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
531 else if constexpr (std::is_same_v<T, std::complex<double>>)
533 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
534 const scalar_value_t<T>*,
const int*,
535 const unsigned char*,
void*)
>(
536 integral->tabulate_tensor_complex128);
542 throw std::runtime_error(
543 "UFCx kernel function is NULL. Check requested types.");
550 assert(topology->index_maps(tdim).at(form_idx));
551 default_cells.resize(
552 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
553 std::iota(default_cells.begin(), default_cells.end(), 0);
555 {k, default_cells, active_coeffs}});
557 else if (sd != subdomains.end())
560 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
561 [](
auto& a) { return a.first; });
562 if (it != sd->second.end() and it->first ==
id)
566 std::vector<std::int32_t>(it->second.begin(),
572 if (integral->needs_facet_permutations)
573 needs_facet_permutations =
true;
579 std::vector<std::int32_t> default_facets_ext;
581 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
585 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
587 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
590 const int id = ids[i];
591 ufcx_integral* integral
594 check_geometry_hash(*integral, form_idx);
596 std::vector<int> active_coeffs;
597 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
599 if (integral->enabled_coefficients[j])
600 active_coeffs.push_back(j);
604 if constexpr (std::is_same_v<T, float>)
605 k = integral->tabulate_tensor_float32;
606#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
607 else if constexpr (std::is_same_v<T, std::complex<float>>)
609 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
610 const scalar_value_t<T>*,
const int*,
611 const unsigned char*,
void*)
>(
612 integral->tabulate_tensor_complex64);
615 else if constexpr (std::is_same_v<T, double>)
616 k = integral->tabulate_tensor_float64;
617#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
618 else if constexpr (std::is_same_v<T, std::complex<double>>)
620 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
621 const scalar_value_t<T>*,
const int*,
622 const unsigned char*,
void*)
>(
623 integral->tabulate_tensor_complex128);
630 auto f_to_c = topology->connectivity(tdim - 1, tdim);
632 auto c_to_f = topology->connectivity(tdim, tdim - 1);
637 default_facets_ext.reserve(2 * bfacets.size());
638 for (std::int32_t f : bfacets)
641 std::array<std::int32_t, 2> pair
643 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
647 {k, default_facets_ext, active_coeffs}});
649 else if (sd != subdomains.end())
652 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
653 [](
auto& a) { return a.first; });
654 if (it != sd->second.end() and it->first ==
id)
658 std::vector<std::int32_t>(it->second.begin(),
664 if (integral->needs_facet_permutations)
665 needs_facet_permutations =
true;
671 std::vector<std::int32_t> default_facets_int;
673 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
677 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
679 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
682 std::vector<std::int8_t> interprocess_marker;
685 assert(topology->index_map(tdim - 1));
686 const std::vector<std::int32_t>& interprocess_facets
687 = topology->interprocess_facets();
688 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
689 + topology->index_map(tdim - 1)->num_ghosts();
690 interprocess_marker.resize(num_facets, 0);
691 std::ranges::for_each(interprocess_facets,
692 [&interprocess_marker](
auto f)
693 { interprocess_marker[f] = 1; });
698 const int id = ids[i];
699 ufcx_integral* integral
702 check_geometry_hash(*integral, form_idx);
704 std::vector<int> active_coeffs;
705 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
707 if (integral->enabled_coefficients[j])
708 active_coeffs.push_back(j);
712 if constexpr (std::is_same_v<T, float>)
713 k = integral->tabulate_tensor_float32;
714#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
715 else if constexpr (std::is_same_v<T, std::complex<float>>)
717 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
718 const scalar_value_t<T>*,
const int*,
719 const unsigned char*,
void*)
>(
720 integral->tabulate_tensor_complex64);
723 else if constexpr (std::is_same_v<T, double>)
724 k = integral->tabulate_tensor_float64;
725#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
726 else if constexpr (std::is_same_v<T, std::complex<double>>)
728 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
729 const scalar_value_t<T>*,
const int*,
730 const unsigned char*,
void*)
>(
731 integral->tabulate_tensor_complex128);
737 auto f_to_c = topology->connectivity(tdim - 1, tdim);
739 auto c_to_f = topology->connectivity(tdim, tdim - 1);
744 assert(topology->index_map(tdim - 1));
745 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
746 default_facets_int.reserve(4 * num_facets);
747 for (std::int32_t f = 0; f < num_facets; ++f)
749 if (f_to_c->num_links(f) == 2)
751 std::array<std::int32_t, 4> pairs
753 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
756 else if (interprocess_marker[f])
758 throw std::runtime_error(
759 "Cannot compute interior facet integral over interprocess "
760 "facet. Please use ghost mode shared facet when creating the "
765 {k, default_facets_int, active_coeffs}});
767 else if (sd != subdomains.end())
769 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
770 [](
auto& a) { return a.first; });
771 if (it != sd->second.end() and it->first ==
id)
775 std::vector<std::int32_t>(it->second.begin(),
781 if (integral->needs_facet_permutations)
782 needs_facet_permutations =
true;
787 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
788 needs_facet_permutations, entity_maps);