414 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
416 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
417 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
420 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
422 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
426 for (
const ufcx_form& ufcx_form : ufcx_forms)
428 if (ufcx_form.rank != (
int)spaces.size())
429 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
430 if (ufcx_form.num_coefficients != (
int)coefficients.size())
432 throw std::runtime_error(
"Mismatch between number of expected and "
433 "provided Form coefficients.");
437 if (ufcx_form.num_constants != (
int)constants.size())
439 throw std::runtime_error(std::format(
440 "Mismatch between number of expected and "
441 "provided Form Constants. Expected {} constants, but got {}.",
442 ufcx_form.num_constants, constants.size()));
444 for (std::size_t c = 0; c < constants.size(); ++c)
446 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
448 throw std::runtime_error(std::format(
449 "Mismatch between expected and actual rank of "
450 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
451 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
453 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
454 ufcx_form.constant_shapes[c]))
456 throw std::runtime_error(
457 std::format(
"Mismatch between expected and actual shape of Form "
458 "Constant for Constant {}.",
465 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
467 for (std::size_t i = 0; i < spaces.size(); ++i)
469 assert(spaces[i]->elements(form_idx));
470 if (
auto element_hash
471 = ufcx_forms[form_idx].get().finite_element_hashes[i];
474 != spaces[i]->elements(form_idx)->basix_element().hash())
476 throw std::runtime_error(
477 "Cannot create form. Elements are different to "
478 "those used to compile the form.");
484 if (!
mesh and !spaces.empty())
485 mesh = spaces.front()->mesh();
487 throw std::runtime_error(
"No mesh could be associated with the Form.");
489 auto topology =
mesh->topology();
491 const int tdim = topology->dim();
496 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
497 std::array<int, 5> num_integrals_type;
498 for (std::size_t i = 0; i < num_integrals_type.size(); ++i)
499 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
502 if (num_integrals_type[
vertex] > 0)
504 mesh->topology_mutable()->create_connectivity(0, tdim);
505 mesh->topology_mutable()->create_connectivity(tdim, 0);
513 mesh->topology_mutable()->create_entities(tdim - 1);
514 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
515 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
519 if (num_integrals_type[
ridge] > 0)
521 mesh->topology_mutable()->create_entities(tdim - 2);
522 mesh->topology_mutable()->create_connectivity(tdim - 2, tdim);
523 mesh->topology_mutable()->create_connectivity(tdim, tdim - 2);
530 auto check_geometry_hash
531 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
532 std::size_t cell_idx)
534 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
536 throw std::runtime_error(
537 "Generated integral geometry element does not match mesh geometry: "
538 + std::to_string(integral.coordinate_element_hash) +
", "
539 + std::to_string(geo.cmaps().at(cell_idx).hash()));
544 bool needs_facet_permutations =
false;
546 std::vector<std::int32_t> default_cells;
547 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
548 + integral_offsets[
cell],
549 num_integrals_type[
cell]);
551 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
553 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
554 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
556 const int id = ids[i];
557 ufcx_integral* integral
558 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
560 check_geometry_hash(*integral, form_idx);
563 std::vector<int> active_coeffs;
564 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
566 if (integral->enabled_coefficients[j])
567 active_coeffs.push_back(j);
570 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
573 throw std::runtime_error(
574 "UFCx kernel function is NULL. Check requested types.");
581 assert(topology->index_maps(tdim).at(form_idx));
582 default_cells.resize(
583 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
584 std::iota(default_cells.begin(), default_cells.end(), 0);
586 {k, default_cells, active_coeffs}});
588 else if (sd != subdomains.end())
591 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
592 [](
auto& a) { return a.first; });
593 if (it != sd->second.end() and it->first ==
id)
597 std::vector<std::int32_t>(it->second.begin(),
603 if (integral->needs_facet_permutations)
604 needs_facet_permutations =
true;
611 std::vector<std::int32_t> default_facets_int;
612 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
616 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
618 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
621 std::vector<std::int8_t> interprocess_marker;
624 assert(topology->index_map(tdim - 1));
625 const std::vector<std::int32_t>& interprocess_facets
626 = topology->interprocess_facets();
627 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
628 + topology->index_map(tdim - 1)->num_ghosts();
629 interprocess_marker.resize(num_facets, 0);
630 std::ranges::for_each(interprocess_facets,
631 [&interprocess_marker](
auto f)
632 { interprocess_marker[f] = 1; });
637 const int id = ids[i];
638 ufcx_integral* integral
641 check_geometry_hash(*integral, form_idx);
643 std::vector<int> active_coeffs;
644 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
646 if (integral->enabled_coefficients[j])
647 active_coeffs.push_back(j);
650 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
654 auto f_to_c = topology->connectivity(tdim - 1, tdim);
656 auto c_to_f = topology->connectivity(tdim, tdim - 1);
661 assert(topology->index_map(tdim - 1));
662 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
663 default_facets_int.reserve(4 * num_facets);
664 for (std::int32_t f = 0; f < num_facets; ++f)
666 if (f_to_c->num_links(f) == 2)
668 std::array<std::int32_t, 4> pairs
669 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
670 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
673 else if (interprocess_marker[f])
675 throw std::runtime_error(
676 "Cannot compute interior facet integral over interprocess "
677 "facet. Please use ghost mode shared facet when creating the "
682 {k, default_facets_int, active_coeffs}});
684 else if (sd != subdomains.end())
686 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
687 [](
auto& a) { return a.first; });
688 if (it != sd->second.end() and it->first ==
id)
692 std::vector<std::int32_t>(it->second.begin(),
698 if (integral->needs_facet_permutations)
699 needs_facet_permutations =
true;
728 throw std::runtime_error(
"Unsupported integral type");
731 const std::function<std::vector<std::int32_t>(
const mesh::Topology&,
733 get_default_integration_entities
744 std::int32_t num_entities = topology.
index_map(dim)->size_local();
745 std::vector<std::int32_t> entities(num_entities);
746 std::iota(entities.begin(), entities.end(), 0);
751 std::vector<std::int32_t> default_entities_ext;
753 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
754 + integral_offsets[(std::int8_t)itg_type],
755 num_integrals_type[(std::int8_t)itg_type]);
756 auto sd = subdomains.find(itg_type);
757 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
759 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
760 for (
int i = 0; i < num_integrals_type[(std::int8_t)itg_type]; ++i)
762 const int id = ids[i];
763 ufcx_integral* integral
764 = ufcx_form.form_integrals[integral_offsets[(std::int8_t)itg_type]
767 check_geometry_hash(*integral, form_idx);
769 std::vector<int> active_coeffs;
770 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
772 if (integral->enabled_coefficients[j])
773 active_coeffs.push_back(j);
776 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
785 std::vector default_entities
786 = get_default_integration_entities(*topology, itg_type);
788 default_entities_ext.reserve(2 * default_entities.size());
789 for (std::int32_t e : default_entities)
792 std::array<std::int32_t, 2> pair = impl::get_cell_entity_pairs<1>(
793 e, e_to_c->links(e), *c_to_e);
794 default_entities_ext.insert(default_entities_ext.end(),
795 pair.begin(), pair.end());
797 integrals.insert({{itg_type, i, form_idx},
798 {k, default_entities_ext, active_coeffs}});
800 else if (sd != subdomains.end())
803 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
804 [](
auto& a) { return a.first; });
805 if (it != sd->second.end() and it->first ==
id)
807 integrals.insert({{itg_type, i, form_idx},
809 std::vector<std::int32_t>(it->second.begin(),
815 if (integral->needs_facet_permutations)
816 needs_facet_permutations =
true;
822 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
823 needs_facet_permutations, entity_maps);