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]}});
296 for (
int i = 0; i < a.num_integrals(type, cell_type_idx); ++i)
299 {extract_cells(a.domain_arg(type, 0, i, 0)),
300 extract_cells(a.domain_arg(type, 1, i, 0))},
301 {{dofmaps[0], dofmaps[1]}});
305 throw std::runtime_error(
"Unsupported integral type");
412 const std::vector<std::reference_wrapper<const ufcx_form>>& ufcx_forms,
414 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
415 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
418 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
420 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
424 for (
const ufcx_form& ufcx_form : ufcx_forms)
426 if (ufcx_form.rank != (
int)spaces.size())
427 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
428 if (ufcx_form.num_coefficients != (
int)coefficients.size())
430 throw std::runtime_error(
"Mismatch between number of expected and "
431 "provided Form coefficients.");
435 if (ufcx_form.num_constants != (
int)constants.size())
437 throw std::runtime_error(std::format(
438 "Mismatch between number of expected and "
439 "provided Form Constants. Expected {} constants, but got {}.",
440 ufcx_form.num_constants, constants.size()));
442 for (std::size_t c = 0; c < constants.size(); ++c)
444 if (ufcx_form.constant_ranks[c] != (
int)constants[c]->shape.size())
446 throw std::runtime_error(std::format(
447 "Mismatch between expected and actual rank of "
448 "Form Constant. Rank of Constant {} should be {}, but got rank {}.",
449 c, ufcx_form.constant_ranks[c], constants[c]->shape.size()));
451 if (!std::equal(constants[c]->shape.begin(), constants[c]->shape.end(),
452 ufcx_form.constant_shapes[c]))
454 throw std::runtime_error(
455 std::format(
"Mismatch between expected and actual shape of Form "
456 "Constant for Constant {}.",
463 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
465 for (std::size_t i = 0; i < spaces.size(); ++i)
467 assert(spaces[i]->elements(form_idx));
468 if (
auto element_hash
469 = ufcx_forms[form_idx].get().finite_element_hashes[i];
472 != spaces[i]->elements(form_idx)->basix_element().hash())
474 throw std::runtime_error(
475 "Cannot create form. Elements are different to "
476 "those used to compile the form.");
482 if (!
mesh and !spaces.empty())
483 mesh = spaces.front()->mesh();
485 throw std::runtime_error(
"No mesh could be associated with the Form.");
487 auto topology =
mesh->topology();
489 const int tdim = topology->dim();
494 const int* integral_offsets = ufcx_forms[0].get().form_integral_offsets;
495 std::array<int, 5> num_integrals_type;
496 for (std::size_t i = 0; i < num_integrals_type.size(); ++i)
497 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
500 if (num_integrals_type[
vertex] > 0)
502 mesh->topology_mutable()->create_connectivity(0, tdim);
503 mesh->topology_mutable()->create_connectivity(tdim, 0);
511 mesh->topology_mutable()->create_entities(tdim - 1);
512 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
513 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
517 if (num_integrals_type[
ridge] > 0)
519 mesh->topology_mutable()->create_entities(tdim - 2);
520 mesh->topology_mutable()->create_connectivity(tdim - 2, tdim);
521 mesh->topology_mutable()->create_connectivity(tdim, tdim - 2);
528 auto check_geometry_hash
529 = [&geo =
mesh->geometry()](
const ufcx_integral& integral,
530 std::size_t cell_idx)
532 if (integral.coordinate_element_hash != geo.cmaps().at(cell_idx).hash())
534 throw std::runtime_error(
535 "Generated integral geometry element does not match mesh geometry: "
536 + std::to_string(integral.coordinate_element_hash) +
", "
537 + std::to_string(geo.cmaps().at(cell_idx).hash()));
542 bool needs_facet_permutations =
false;
544 std::vector<std::int32_t> default_cells;
545 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
546 + integral_offsets[
cell],
547 num_integrals_type[
cell]);
549 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
551 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
552 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
554 const int id = ids[i];
555 ufcx_integral* integral
556 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
558 check_geometry_hash(*integral, form_idx);
561 std::vector<int> active_coeffs;
562 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
564 if (integral->enabled_coefficients[j])
565 active_coeffs.push_back(j);
568 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
571 throw std::runtime_error(
572 "UFCx kernel function is NULL. Check requested types.");
579 assert(topology->index_maps(tdim).at(form_idx));
580 default_cells.resize(
581 topology->index_maps(tdim).at(form_idx)->size_local(), 0);
582 std::iota(default_cells.begin(), default_cells.end(), 0);
584 {k, default_cells, active_coeffs}});
586 else if (sd != subdomains.end())
589 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
590 [](
auto& a) { return a.first; });
591 if (it != sd->second.end() and it->first ==
id)
595 std::vector<std::int32_t>(it->second.begin(),
601 if (integral->needs_facet_permutations)
602 needs_facet_permutations =
true;
609 std::vector<std::int32_t> default_facets_int;
610 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
614 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
616 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
619 std::vector<std::int8_t> interprocess_marker;
622 assert(topology->index_map(tdim - 1));
623 const std::vector<std::int32_t>& interprocess_facets
624 = topology->interprocess_facets();
625 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
626 + topology->index_map(tdim - 1)->num_ghosts();
627 interprocess_marker.resize(num_facets, 0);
628 std::ranges::for_each(interprocess_facets,
629 [&interprocess_marker](
auto f)
630 { interprocess_marker[f] = 1; });
635 const int id = ids[i];
636 ufcx_integral* integral
639 check_geometry_hash(*integral, form_idx);
641 std::vector<int> active_coeffs;
642 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
644 if (integral->enabled_coefficients[j])
645 active_coeffs.push_back(j);
648 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
652 auto f_to_c = topology->connectivity(tdim - 1, tdim);
654 auto c_to_f = topology->connectivity(tdim, tdim - 1);
659 assert(topology->index_map(tdim - 1));
660 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
661 default_facets_int.reserve(4 * num_facets);
662 for (std::int32_t f = 0; f < num_facets; ++f)
664 if (f_to_c->num_links(f) == 2)
666 std::array<std::int32_t, 4> pairs
667 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
668 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
671 else if (interprocess_marker[f])
673 throw std::runtime_error(
674 "Cannot compute interior facet integral over interprocess "
675 "facet. Please use ghost mode shared facet when creating the "
680 {k, default_facets_int, active_coeffs}});
682 else if (sd != subdomains.end())
684 auto it = std::ranges::lower_bound(sd->second,
id, std::less{},
685 [](
auto& a) { return a.first; });
686 if (it != sd->second.end() and it->first ==
id)
690 std::vector<std::int32_t>(it->second.begin(),
696 if (integral->needs_facet_permutations)
697 needs_facet_permutations =
true;
726 throw std::runtime_error(
"Unsupported integral type");
729 const std::function<std::vector<std::int32_t>(
const mesh::Topology&,
731 get_default_integration_entities
742 std::int32_t num_entities = topology.
index_map(dim)->size_local();
743 std::vector<std::int32_t> entities(num_entities);
744 std::iota(entities.begin(), entities.end(), 0);
749 std::vector<std::int32_t> default_entities_ext;
751 std::span<const int> ids(ufcx_forms[0].get().form_integral_ids
752 + integral_offsets[(std::int8_t)itg_type],
753 num_integrals_type[(std::int8_t)itg_type]);
754 auto sd = subdomains.find(itg_type);
755 for (std::size_t form_idx = 0; form_idx < ufcx_forms.size(); ++form_idx)
757 const ufcx_form& ufcx_form = ufcx_forms[form_idx];
758 for (
int i = 0; i < num_integrals_type[(std::int8_t)itg_type]; ++i)
760 const int id = ids[i];
761 ufcx_integral* integral
762 = ufcx_form.form_integrals[integral_offsets[(std::int8_t)itg_type]
765 check_geometry_hash(*integral, form_idx);
767 std::vector<int> active_coeffs;
768 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
770 if (integral->enabled_coefficients[j])
771 active_coeffs.push_back(j);
774 impl::kernel_t<T, U> k = impl::extract_kernel<T>(integral);
783 std::vector default_entities
784 = get_default_integration_entities(*topology, itg_type);
786 default_entities_ext.reserve(2 * default_entities.size());
787 for (std::int32_t e : default_entities)
790 std::array<std::int32_t, 2> pair = impl::get_cell_entity_pairs<1>(
791 e, e_to_c->links(e), *c_to_e);
792 default_entities_ext.insert(default_entities_ext.end(),
793 pair.begin(), pair.end());
795 integrals.insert({{itg_type, i, form_idx},
796 {k, default_entities_ext, active_coeffs}});
798 else if (sd != subdomains.end())
801 auto it = std::ranges::lower_bound(sd->second,
id, std::less<>{},
802 [](
auto& a) { return a.first; });
803 if (it != sd->second.end() and it->first ==
id)
805 integrals.insert({{itg_type, i, form_idx},
807 std::vector<std::int32_t>(it->second.begin(),
813 if (integral->needs_facet_permutations)
814 needs_facet_permutations =
true;
820 return Form<T, U>(spaces, std::move(integrals),
mesh, coefficients, constants,
821 needs_facet_permutations, entity_maps);