229 throw std::runtime_error(
230 "Cannot create sparsity pattern. Form is not a bilinear.");
233 std::shared_ptr
mesh = a.mesh();
235 std::shared_ptr mesh0 = a.function_spaces().at(0)->mesh();
237 std::shared_ptr mesh1 = a.function_spaces().at(1)->mesh();
240 const std::set<IntegralType> types = a.integral_types();
245 int tdim =
mesh->topology()->dim();
246 mesh->topology_mutable()->create_entities(tdim - 1);
247 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
252 auto extract_cells = [](std::span<const std::int32_t> facets)
254 assert(facets.size() % 2 == 0);
255 std::vector<std::int32_t> cells;
256 cells.reserve(facets.size() / 2);
257 for (std::size_t i = 0; i < facets.size(); i += 2)
258 cells.push_back(facets[i]);
262 const int num_cell_types =
mesh->topology()->cell_types().size();
263 for (
int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
265 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
266 *a.function_spaces().at(0)->dofmaps(cell_type_idx),
267 *a.function_spaces().at(1)->dofmaps(cell_type_idx)};
270 for (
auto type : types)
275 for (
int i = 0; i < a.num_integrals(type, cell_type_idx); ++i)
278 {a.domain_arg(type, 0, i, cell_type_idx),
279 a.domain_arg(type, 1, i, cell_type_idx)},
280 {{dofmaps[0], dofmaps[1]}});
284 for (
int i = 0; i < a.num_integrals(type, cell_type_idx); ++i)
288 {extract_cells(a.domain_arg(type, 0, i, 0)),
289 extract_cells(a.domain_arg(type, 1, i, 0))},
290 {{dofmaps[0], dofmaps[1]}});
294 for (
int i = 0; i < a.num_integrals(type, cell_type_idx); ++i)
297 {extract_cells(a.domain_arg(type, 0, i, 0)),
298 extract_cells(a.domain_arg(type, 1, i, 0))},
299 {{dofmaps[0], dofmaps[1]}});
303 throw std::runtime_error(
"Unsupported integral type");
410 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
412 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
413 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
416 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
418 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
422 for (
const ufcx_form& ufcx_form : ufcx_forms)
424 if (ufcx_form.rank != (
int)spaces.size())
425 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
426 if (ufcx_form.num_coefficients != (
int)coefficients.size())
428 throw std::runtime_error(
"Mismatch between number of expected and "
429 "provided Form coefficients.");
433 if (ufcx_form.num_constants != (
int)constants.size())
435 throw std::runtime_error(std::format(
436 "Mismatch between number of expected and "
437 "provided Form Constants. Expected {} constants, but got {}.",
438 ufcx_form.num_constants, constants.size()));
440 for (std::size_t c = 0; c < constants.size(); ++c)
442 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
444 throw std::runtime_error(std::format(
445 "Mismatch between expected and actual rank of "
446 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
447 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
449 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
450 ufcx_form.constant_shapes[c]))
452 throw std::runtime_error(
453 std::format(
"Mismatch between expected and actual shape of Form "
454 "Constant for Constant {}.",
461 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
463 for (std::size_t i = 0; i < spaces.size(); ++i)
465 assert(spaces[i]->elements(form_idx));
466 if (
auto element_hash
467 = ufcx_forms[form_idx].get().finite_element_hashes[i];
470 != spaces[i]->elements(form_idx)->basix_element().hash())
472 throw std::runtime_error(
473 "Cannot create form. Elements are different to "
474 "those used to compile the form.");
480 if (!
mesh and !spaces.empty())
481 mesh = spaces.front()->mesh();
483 throw std::runtime_error(
"No mesh could be associated with the Form.");
485 auto topology =
mesh->topology();
487 const int tdim = topology->dim();
492 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
493 std::array<int, 4> num_integrals_type;
494 for (std::size_t i = 0; i < num_integrals_type.size(); ++i)
495 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
498 if (num_integrals_type[
vertex] > 0)
500 mesh->topology_mutable()->create_connectivity(0, tdim);
501 mesh->topology_mutable()->create_connectivity(tdim, 0);
508 mesh->topology_mutable()->create_entities(tdim - 1);
509 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
510 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
517 auto check_geometry_hash
518 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
519 std::size_t cell_idx)
521 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
523 throw std::runtime_error(
524 "Generated integral geometry element does not match mesh geometry: "
525 + std::to_string(integral.coordinate_element_hash) +
", "
526 + std::to_string(geo.cmaps().at(cell_idx).hash()));
531 bool needs_facet_permutations =
false;
533 std::vector<std::int32_t> default_cells;
534 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
535 + integral_offsets[
cell],
536 num_integrals_type[
cell]);
538 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
540 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
541 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
543 const int id = ids[i];
544 ufcx_integral* integral
545 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
547 check_geometry_hash(*integral, form_idx);
550 std::vector<int> active_coeffs;
551 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
553 if (integral->enabled_coefficients[j])
554 active_coeffs.push_back(j);
557 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
560 throw std::runtime_error(
561 "UFCx kernel function is NULL. Check requested types.");
568 assert(topology->index_maps(tdim).at(form_idx));
569 default_cells.resize(
570 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
571 std::iota(default_cells.begin(), default_cells.end(), 0);
573 {k, default_cells, active_coeffs}});
575 else if (sd != subdomains.end())
578 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
579 [](
auto& a) { return a.first; });
580 if (it != sd->second.end() and it->first ==
id)
584 std::vector<std::int32_t>(it->second.begin(),
590 if (integral->needs_facet_permutations)
591 needs_facet_permutations =
true;
597 std::vector<std::int32_t> default_facets_ext;
599 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
603 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
605 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
608 const int id = ids[i];
609 ufcx_integral* integral
612 check_geometry_hash(*integral, form_idx);
614 std::vector<int> active_coeffs;
615 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
617 if (integral->enabled_coefficients[j])
618 active_coeffs.push_back(j);
621 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
625 auto f_to_c = topology->connectivity(tdim - 1, tdim);
627 auto c_to_f = topology->connectivity(tdim, tdim - 1);
632 default_facets_ext.reserve(2 * bfacets.size());
633 for (std::int32_t f : bfacets)
636 std::array<std::int32_t, 2> pair
637 = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
638 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
642 {k, default_facets_ext, active_coeffs}});
644 else if (sd != subdomains.end())
647 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
648 [](
auto& a) { return a.first; });
649 if (it != sd->second.end() and it->first ==
id)
653 std::vector<std::int32_t>(it->second.begin(),
659 if (integral->needs_facet_permutations)
660 needs_facet_permutations =
true;
666 std::vector<std::int32_t> default_facets_int;
668 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
672 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
674 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
677 std::vector<std::int8_t> interprocess_marker;
680 assert(topology->index_map(tdim - 1));
681 const std::vector<std::int32_t>& interprocess_facets
682 = topology->interprocess_facets();
683 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
684 + topology->index_map(tdim - 1)->num_ghosts();
685 interprocess_marker.resize(num_facets, 0);
686 std::ranges::for_each(interprocess_facets,
687 [&interprocess_marker](
auto f)
688 { interprocess_marker[f] = 1; });
693 const int id = ids[i];
694 ufcx_integral* integral
697 check_geometry_hash(*integral, form_idx);
699 std::vector<int> active_coeffs;
700 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
702 if (integral->enabled_coefficients[j])
703 active_coeffs.push_back(j);
706 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
710 auto f_to_c = topology->connectivity(tdim - 1, tdim);
712 auto c_to_f = topology->connectivity(tdim, tdim - 1);
717 assert(topology->index_map(tdim - 1));
718 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
719 default_facets_int.reserve(4 * num_facets);
720 for (std::int32_t f = 0; f < num_facets; ++f)
722 if (f_to_c->num_links(f) == 2)
724 std::array<std::int32_t, 4> pairs
725 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
726 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
729 else if (interprocess_marker[f])
731 throw std::runtime_error(
732 "Cannot compute interior facet integral over interprocess "
733 "facet. Please use ghost mode shared facet when creating the "
738 {k, default_facets_int, active_coeffs}});
740 else if (sd != subdomains.end())
742 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
743 [](
auto& a) { return a.first; });
744 if (it != sd->second.end() and it->first ==
id)
748 std::vector<std::int32_t>(it->second.begin(),
754 if (integral->needs_facet_permutations)
755 needs_facet_permutations =
true;
762 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
764 const ufcx_form& form = ufcx_forms[form_idx];
766 std::span<const int> ids(form.form_integral_ids
767 + integral_offsets[
vertex],
768 num_integrals_type[
vertex]);
770 for (
int i = 0; i < num_integrals_type[
vertex]; ++i)
772 const int id = ids[i];
773 ufcx_integral* integral
774 = form.form_integrals[integral_offsets[
vertex] + i];
776 check_geometry_hash(*integral, form_idx);
778 std::vector<int> active_coeffs;
779 for (
int j = 0; j < form.num_coefficients; ++j)
781 if (integral->enabled_coefficients[j])
782 active_coeffs.push_back(j);
785 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
789 auto v_to_c = topology->connectivity(0, tdim);
791 auto c_to_v = topology->connectivity(tdim, 0);
797 auto get_cells_and_vertices = [v_to_c, c_to_v](
auto vertices_range)
799 std::vector<std::int32_t> cell_and_vertex;
800 cell_and_vertex.reserve(2 * vertices_range.size());
801 for (std::int32_t
vertex : vertices_range)
803 std::array<std::int32_t, 2> pair = impl::get_cell_vertex_pairs<1>(
806 cell_and_vertex.insert(cell_and_vertex.end(), pair.begin(),
809 assert(cell_and_vertex.size() == 2 * vertices_range.size());
810 return cell_and_vertex;
816 std::int32_t num_vertices = topology->index_map(0)->size_local();
817 std::vector<std::int32_t> cells_and_vertices = get_cells_and_vertices(
818 std::ranges::views::iota(0, num_vertices));
821 {k, cells_and_vertices, active_coeffs}});
823 else if (sd != subdomains.end())
826 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
827 [](
auto& a) { return a.first; });
828 if (it != sd->second.end() and it->first ==
id)
832 std::vector<std::int32_t>(it->second.begin(),
841 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
842 needs_facet_permutations, entity_maps);