10#include "CoordinateElement.h"
12#include "ElementDofLayout.h"
13#include "Expression.h"
16#include "FunctionSpace.h"
17#include "sparsitybuild.h"
21#include <dolfinx/common/types.h>
22#include <dolfinx/la/SparsityPattern.h>
23#include <dolfinx/mesh/Topology.h>
24#include <dolfinx/mesh/cell_types.h>
41template <std::
floating_po
int T>
61template <
int num_cells>
62std::array<std::int32_t, 2 * num_cells>
67 assert(cells.size() == num_cells);
68 std::array<std::int32_t, 2 * num_cells> cell_local_facet_pairs;
69 for (
int c = 0; c < num_cells; ++c)
72 std::int32_t
cell = cells[c];
74 auto facet_it = std::find(cell_facets.begin(), cell_facets.end(), f);
75 assert(facet_it != cell_facets.end());
76 int local_f = std::distance(cell_facets.begin(), facet_it);
77 cell_local_facet_pairs[2 * c] =
cell;
78 cell_local_facet_pairs[2 * c + 1] = local_f;
81 return cell_local_facet_pairs;
108std::vector<std::int32_t>
111 std::span<const std::int32_t> entities,
int dim);
120template <dolfinx::scalar T, std::
floating_po
int U>
121std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
125 std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
130 for (std::size_t i = 0; i < a.size(); ++i)
132 for (std::size_t j = 0; j < a[i].size(); ++j)
135 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
146template <dolfinx::scalar T, std::
floating_po
int U>
151 throw std::runtime_error(
152 "Cannot create sparsity pattern. Form is not a bilinear.");
156 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
157 *a.function_spaces().at(0)->dofmap(),
158 *a.function_spaces().at(1)->dofmap()};
159 std::shared_ptr mesh = a.mesh();
162 std::shared_ptr mesh0 = a.function_spaces().at(0)->mesh();
164 std::shared_ptr mesh1 = a.function_spaces().at(1)->mesh();
167 const std::set<IntegralType> types = a.integral_types();
172 int tdim = mesh->topology()->dim();
173 mesh->topology_mutable()->create_entities(tdim - 1);
174 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
180 const std::array index_maps{dofmaps[0].get().index_map,
181 dofmaps[1].get().index_map};
183 = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
185 auto extract_cells = [](std::span<const std::int32_t> facets)
187 assert(facets.size() % 2 == 0);
188 std::vector<std::int32_t> cells;
189 cells.reserve(facets.size() / 2);
190 for (std::size_t i = 0; i < facets.size(); i += 2)
191 cells.push_back(facets[i]);
197 for (
auto type : types)
199 std::vector<int> ids = a.integral_ids(type);
206 pattern, {a.domain(type,
id, *mesh0), a.domain(type,
id, *mesh1)},
207 {{dofmaps[0], dofmaps[1]}});
215 {extract_cells(a.domain(type,
id, *mesh0)),
216 extract_cells(a.domain(type,
id, *mesh1))},
217 {{dofmaps[0], dofmaps[1]}});
224 {extract_cells(a.domain(type,
id, *mesh0)),
225 extract_cells(a.domain(type,
id, *mesh1))},
226 {{dofmaps[0], dofmaps[1]}});
230 throw std::runtime_error(
"Unsupported integral type");
240template <std::
floating_po
int T>
242 const std::vector<int>& parent_map
246 std::vector<int> offsets(1, 0);
247 std::vector<dolfinx::fem::ElementDofLayout> sub_doflayout;
248 int bs = element.block_size();
249 for (
int i = 0; i < element.num_sub_elements(); ++i)
254 std::shared_ptr<const fem::FiniteElement<T>> sub_e
255 = element.sub_elements()[bs > 1 ? 0 : i];
261 std::vector<int> parent_map_sub(sub_e->space_dimension(), offsets.back());
262 for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
263 parent_map_sub[j] += bs * j;
264 offsets.push_back(offsets.back() + (bs > 1 ? 1 : sub_e->space_dimension()));
265 sub_doflayout.push_back(
269 return ElementDofLayout(bs, element.entity_dofs(),
270 element.entity_closure_dofs(), parent_map,
283 MPI_Comm comm,
const ElementDofLayout& layout, mesh::Topology& topology,
284 std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
285 std::function<std::vector<int>(
const graph::AdjacencyList<std::int32_t>&)>
299 MPI_Comm comm,
const std::vector<ElementDofLayout>& layouts,
300 mesh::Topology& topology,
301 std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
302 std::function<std::vector<int>(
const graph::AdjacencyList<std::int32_t>&)>
332template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
334 const ufcx_form& ufcx_form,
336 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
337 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
340 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
343 std::span<const std::int32_t>>& entity_maps,
346 if (ufcx_form.rank != (
int)spaces.size())
347 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
348 if (ufcx_form.num_coefficients != (
int)coefficients.size())
350 throw std::runtime_error(
351 "Mismatch between number of expected and provided Form coefficients.");
353 if (ufcx_form.num_constants != (
int)constants.size())
355 throw std::runtime_error(
356 "Mismatch between number of expected and provided Form constants.");
360 for (std::size_t i = 0; i < spaces.size(); ++i)
362 assert(spaces[i]->element());
363 if (
auto element_hash = ufcx_form.finite_element_hashes[i];
365 and element_hash != spaces[i]->element()->basix_element().hash())
367 throw std::runtime_error(
"Cannot create form. Elements are different to "
368 "those used to compile the form.");
373 if (!mesh and !spaces.empty())
374 mesh = spaces[0]->mesh();
375 for (
auto& V : spaces)
377 if (mesh != V->mesh() and entity_maps.find(V->mesh()) == entity_maps.end())
378 throw std::runtime_error(
379 "Incompatible mesh. entity_maps must be provided.");
382 throw std::runtime_error(
"No mesh could be associated with the Form.");
384 auto topology = mesh->topology();
386 const int tdim = topology->dim();
388 const int* integral_offsets = ufcx_form.form_integral_offsets;
389 std::vector<int> num_integrals_type(3);
390 for (
int i = 0; i < 3; ++i)
391 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
397 mesh->topology_mutable()->create_entities(tdim - 1);
398 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
399 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
404 using kern_t = std::function<void(T*,
const T*,
const T*,
const U*,
405 const int*,
const std::uint8_t*)>;
406 std::map<IntegralType, std::vector<integral_data<T, U>>> integrals;
409 bool needs_facet_permutations =
false;
410 std::vector<std::int32_t> default_cells;
412 std::span<const int> ids(ufcx_form.form_integral_ids
413 + integral_offsets[
cell],
414 num_integrals_type[
cell]);
417 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
419 const int id = ids[i];
420 ufcx_integral* integral
421 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
425 std::vector<int> active_coeffs;
426 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
428 if (integral->enabled_coefficients[j])
429 active_coeffs.push_back(j);
433 if constexpr (std::is_same_v<T, float>)
434 k = integral->tabulate_tensor_float32;
435#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
436 else if constexpr (std::is_same_v<T, std::complex<float>>)
438 k =
reinterpret_cast<void (*)(
439 T*,
const T*,
const T*,
440 const typename scalar_value_type<T>::value_type*,
const int*,
441 const unsigned char*)
>(integral->tabulate_tensor_complex64);
444 else if constexpr (std::is_same_v<T, double>)
445 k = integral->tabulate_tensor_float64;
446#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
447 else if constexpr (std::is_same_v<T, std::complex<double>>)
449 k =
reinterpret_cast<void (*)(
450 T*,
const T*,
const T*,
451 const typename scalar_value_type<T>::value_type*,
const int*,
452 const unsigned char*)
>(integral->tabulate_tensor_complex128);
458 throw std::runtime_error(
459 "UFCx kernel function is NULL. Check requested types.");
466 assert(topology->index_map(tdim));
467 default_cells.resize(topology->index_map(tdim)->size_local(), 0);
468 std::iota(default_cells.begin(), default_cells.end(), 0);
469 itg.first->second.emplace_back(
id, k, default_cells, active_coeffs);
471 else if (sd != subdomains.end())
475 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
476 [](
const auto& a) { return a.first; });
477 if (it != sd->second.end() and it->first ==
id)
478 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
481 if (integral->needs_facet_permutations)
482 needs_facet_permutations =
true;
487 std::vector<std::int32_t> default_facets_ext;
489 std::span<const int> ids(ufcx_form.form_integral_ids
496 const int id = ids[i];
497 ufcx_integral* integral
500 std::vector<int> active_coeffs;
501 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
503 if (integral->enabled_coefficients[j])
504 active_coeffs.push_back(j);
508 if constexpr (std::is_same_v<T, float>)
509 k = integral->tabulate_tensor_float32;
510#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
511 else if constexpr (std::is_same_v<T, std::complex<float>>)
513 k =
reinterpret_cast<void (*)(
514 T*,
const T*,
const T*,
515 const typename scalar_value_type<T>::value_type*,
const int*,
516 const unsigned char*)
>(integral->tabulate_tensor_complex64);
519 else if constexpr (std::is_same_v<T, double>)
520 k = integral->tabulate_tensor_float64;
521#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
522 else if constexpr (std::is_same_v<T, std::complex<double>>)
524 k =
reinterpret_cast<void (*)(
525 T*,
const T*,
const T*,
526 const typename scalar_value_type<T>::value_type*,
const int*,
527 const unsigned char*)
>(integral->tabulate_tensor_complex128);
534 auto f_to_c = topology->connectivity(tdim - 1, tdim);
536 auto c_to_f = topology->connectivity(tdim, tdim - 1);
541 default_facets_ext.reserve(2 * bfacets.size());
542 for (std::int32_t f : bfacets)
546 = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
547 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
550 itg.first->second.emplace_back(
id, k, default_facets_ext,
553 else if (sd != subdomains.end())
557 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
558 [](
const auto& a) { return a.first; });
559 if (it != sd->second.end() and it->first ==
id)
560 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
563 if (integral->needs_facet_permutations)
564 needs_facet_permutations =
true;
569 std::vector<std::int32_t> default_facets_int;
571 std::span<const int> ids(ufcx_form.form_integral_ids
578 std::vector<std::int8_t> interprocess_marker;
581 assert(topology->index_map(tdim - 1));
582 const std::vector<std::int32_t>& interprocess_facets
583 = topology->interprocess_facets();
584 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
585 + topology->index_map(tdim - 1)->num_ghosts();
586 interprocess_marker.resize(num_facets, 0);
587 std::ranges::for_each(interprocess_facets, [&interprocess_marker](
auto f)
588 { interprocess_marker[f] = 1; });
593 const int id = ids[i];
594 ufcx_integral* integral
597 std::vector<int> active_coeffs;
598 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
600 if (integral->enabled_coefficients[j])
601 active_coeffs.push_back(j);
605 if constexpr (std::is_same_v<T, float>)
606 k = integral->tabulate_tensor_float32;
607#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
608 else if constexpr (std::is_same_v<T, std::complex<float>>)
610 k =
reinterpret_cast<void (*)(
611 T*,
const T*,
const T*,
612 const typename scalar_value_type<T>::value_type*,
const int*,
613 const unsigned char*)
>(integral->tabulate_tensor_complex64);
616 else if constexpr (std::is_same_v<T, double>)
617 k = integral->tabulate_tensor_float64;
618#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
619 else if constexpr (std::is_same_v<T, std::complex<double>>)
621 k =
reinterpret_cast<void (*)(
622 T*,
const T*,
const T*,
623 const typename scalar_value_type<T>::value_type*,
const int*,
624 const unsigned char*)
>(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 assert(topology->index_map(tdim - 1));
638 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
639 default_facets_int.reserve(4 * num_facets);
640 for (std::int32_t f = 0; f < num_facets; ++f)
642 if (f_to_c->num_links(f) == 2)
645 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
646 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
649 else if (interprocess_marker[f])
651 throw std::runtime_error(
652 "Cannot compute interior facet integral over interprocess "
653 "facet. Please use ghost mode shared facet when creating the "
657 itg.first->second.emplace_back(
id, k, default_facets_int,
660 else if (sd != subdomains.end())
663 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
664 [](
const auto& a) { return a.first; });
665 if (it != sd->second.end() and it->first ==
id)
666 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
669 if (integral->needs_facet_permutations)
670 needs_facet_permutations =
true;
675 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>
677 for (
auto& [itg, data] : subdomains)
679 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>> x;
680 for (
auto& [
id, idx] : data)
681 x.emplace_back(
id, std::vector(idx.data(), idx.data() + idx.size()));
682 sd.insert({itg, std::move(x)});
685 return Form<T, U>(spaces, integrals, coefficients, constants,
686 needs_facet_permutations, entity_maps, mesh);
702template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
704 const ufcx_form& ufcx_form,
706 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
708 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
711 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
714 std::span<const std::int32_t>>& entity_maps,
718 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
721 if (
auto it = coefficients.find(name); it != coefficients.end())
722 coeff_map.push_back(it->second);
725 throw std::runtime_error(
"Form coefficient \"" + name
726 +
"\" not provided.");
732 std::vector<std::shared_ptr<const Constant<T>>> const_map;
735 if (
auto it = constants.find(name); it != constants.end())
736 const_map.push_back(it->second);
738 throw std::runtime_error(
"Form constant \"" + name +
"\" not provided.");
742 subdomains, entity_maps, mesh);
762template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
764 ufcx_form* (*fptr)(),
766 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
768 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
771 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
774 std::span<const std::int32_t>>& entity_maps,
777 ufcx_form* form = fptr();
779 subdomains, entity_maps, mesh);
795template <std::
floating_po
int T>
798 const std::vector<std::size_t>& value_shape = {},
803 if (!e.value_shape().empty() and !value_shape.empty())
805 throw std::runtime_error(
806 "Cannot specify value shape for non-scalar base element.");
810 != mesh->topology()->cell_type())
811 throw std::runtime_error(
"Cell type of element and mesh must match.");
813 std::size_t bs = value_shape.empty()
815 : std::accumulate(value_shape.begin(), value_shape.end(),
816 1, std::multiplies{});
819 auto _e = std::make_shared<const FiniteElement<T>>(e, bs);
822 const std::vector<std::size_t> _value_shape
823 = (value_shape.empty() and !e.value_shape().empty())
825 mesh->geometry().dim())
829 const int num_sub_elements = _e->num_sub_elements();
830 std::vector<ElementDofLayout> sub_doflayout;
831 sub_doflayout.reserve(num_sub_elements);
832 for (
int i = 0; i < num_sub_elements; ++i)
834 auto sub_element = _e->extract_sub_element({i});
835 std::vector<int> parent_map_sub(sub_element->space_dimension());
836 for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
837 parent_map_sub[j] = i + _e->block_size() * j;
838 sub_doflayout.emplace_back(1, e.entity_dofs(), e.entity_closure_dofs(),
839 parent_map_sub, std::vector<ElementDofLayout>());
843 ElementDofLayout layout(_e->block_size(), e.entity_dofs(),
844 e.entity_closure_dofs(), {}, sub_doflayout);
845 std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv
847 if (_e->needs_dof_permutations())
848 permute_inv = _e->dof_permutation_fn(
true,
true);
850 assert(mesh->topology());
852 mesh->comm(), layout, *mesh->topology(), permute_inv, reorder_fn));
860template <dolfinx::scalar T, std::
floating_po
int U>
861std::span<const std::uint32_t>
862get_cell_orientation_info(
const Function<T, U>& coefficient)
864 std::span<const std::uint32_t> cell_info;
865 auto element = coefficient.function_space()->element();
866 if (element->needs_dof_transformations())
868 auto mesh = coefficient.function_space()->mesh();
869 mesh->topology_mutable()->create_entity_permutations();
870 cell_info = std::span(mesh->topology()->get_cell_permutation_info());
877template <
int _bs, dolfinx::scalar T>
878void pack(std::span<T> coeffs, std::int32_t
cell,
int bs, std::span<const T> v,
879 std::span<const std::uint32_t> cell_info,
const DofMap& dofmap,
883 for (std::size_t i = 0; i < dofs.size(); ++i)
885 if constexpr (_bs < 0)
887 const int pos_c = bs * i;
888 const int pos_v = bs * dofs[i];
889 for (
int k = 0; k < bs; ++k)
890 coeffs[pos_c + k] = v[pos_v + k];
895 const int pos_c = _bs * i;
896 const int pos_v = _bs * dofs[i];
897 for (
int k = 0; k < _bs; ++k)
898 coeffs[pos_c + k] = v[pos_v + k];
902 transform(coeffs, cell_info,
cell, 1);
908concept FetchCells =
requires(F&& f, std::span<const std::int32_t> v) {
909 requires std::invocable<F, std::span<const std::int32_t>>;
910 { f(v) } -> std::convertible_to<std::int32_t>;
926template <dolfinx::scalar T, std::
floating_po
int U>
929 std::span<const std::uint32_t> cell_info,
930 std::span<const std::int32_t> entities,
931 std::size_t estride,
FetchCells auto&& fetch_cells,
935 std::span<const T> v = u.x()->array();
936 const DofMap& dofmap = *u.function_space()->dofmap();
937 auto element = u.function_space()->element();
939 int space_dim = element->space_dimension();
945 const int bs = dofmap.
bs();
949 for (std::size_t e = 0; e < entities.size(); e += estride)
951 auto entity = entities.subspan(e, estride);
952 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
955 = c.subspan((e / estride) * cstride + offset, space_dim);
956 pack<1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
961 for (std::size_t e = 0; e < entities.size(); e += estride)
963 auto entity = entities.subspan(e, estride);
964 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
967 = c.subspan((e / estride) * cstride + offset, space_dim);
968 pack<2>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
973 for (std::size_t e = 0; e < entities.size(); e += estride)
975 auto entity = entities.subspan(e, estride);
976 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
978 auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
979 pack<3>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
984 for (std::size_t e = 0; e < entities.size(); e += estride)
986 auto entity = entities.subspan(e, estride);
987 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
990 = c.subspan((e / estride) * cstride + offset, space_dim);
991 pack<-1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
1006template <dolfinx::scalar T, std::
floating_po
int U>
1007std::pair<std::vector<T>,
int>
1012 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
1016 std::size_t num_entities = 0;
1018 if (!coefficients.empty())
1020 cstride = offsets.back();
1021 num_entities = form.
domain(integral_type,
id).size();
1029 return {std::vector<T>(num_entities * cstride), cstride};
1036template <dolfinx::scalar T, std::
floating_po
int U>
1037std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>>
1040 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>> coeffs;
1045 coeffs.emplace_hint(
1046 coeffs.end(), std::pair(integral_type,
id),
1061template <dolfinx::scalar T, std::
floating_po
int U>
1063 int id, std::span<T> c,
int cstride)
1066 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
1071 std::vector<int> active_coefficient(coefficients.size(), 0);
1072 if (!coefficients.empty())
1074 switch (integral_type)
1083 active_coefficient[idx] = 1;
1087 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1089 if (!active_coefficient[coeff])
1093 auto mesh = coefficients[coeff]->function_space()->mesh();
1100 = form.
mesh()->topology()->dim() - mesh->topology()->dim();
1103 throw std::runtime_error(
"Should not be packing coefficients with "
1104 "codim>0 in a cell integral");
1107 std::vector<std::int32_t> cells
1109 std::span<const std::uint32_t> cell_info
1110 = impl::get_cell_orientation_info(*coefficients[coeff]);
1111 impl::pack_coefficient_entity(
1112 c, cstride, *coefficients[coeff], cell_info, cells, 1,
1113 [](
auto entity) {
return entity.front(); }, offsets[coeff]);
1121 for (std::size_t i = 0;
1125 active_coefficient[idx] = 1;
1129 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1131 if (!active_coefficient[coeff])
1134 auto mesh = coefficients[coeff]->function_space()->mesh();
1135 std::vector<std::int32_t> facets
1137 std::span<const std::uint32_t> cell_info
1138 = impl::get_cell_orientation_info(*coefficients[coeff]);
1139 impl::pack_coefficient_entity(
1140 c, cstride, *coefficients[coeff], cell_info, facets, 2,
1141 [](
auto entity) {
return entity.front(); }, offsets[coeff]);
1149 for (std::size_t i = 0;
1153 active_coefficient[idx] = 1;
1157 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1159 if (!active_coefficient[coeff])
1162 auto mesh = coefficients[coeff]->function_space()->mesh();
1163 std::vector<std::int32_t> facets
1166 std::span<const std::uint32_t> cell_info
1167 = impl::get_cell_orientation_info(*coefficients[coeff]);
1170 impl::pack_coefficient_entity(
1171 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1172 [](
auto entity) {
return entity[0]; }, 2 * offsets[coeff]);
1175 impl::pack_coefficient_entity(
1176 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1177 [](
auto entity) {
return entity[2]; },
1178 offsets[coeff] + offsets[coeff + 1]);
1183 throw std::runtime_error(
1184 "Could not pack coefficient. Integral type not supported.");
1190template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
1192 const ufcx_expression& e,
1193 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
1194 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
1197 if (e.rank > 0 and !argument_function_space)
1199 throw std::runtime_error(
"Expression has Argument but no Argument "
1200 "function space was provided.");
1203 std::vector<U> X(e.points, e.points + e.num_points * e.entity_dimension);
1204 std::array<std::size_t, 2> Xshape
1205 = {
static_cast<std::size_t
>(e.num_points),
1206 static_cast<std::size_t
>(e.entity_dimension)};
1207 std::vector<int> value_shape(e.value_shape, e.value_shape + e.num_components);
1208 std::function<void(T*,
const T*,
const T*,
1209 const typename scalar_value_type<T>::value_type*,
1210 const int*,
const std::uint8_t*)>
1211 tabulate_tensor =
nullptr;
1212 if constexpr (std::is_same_v<T, float>)
1213 tabulate_tensor = e.tabulate_tensor_float32;
1214#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1215 else if constexpr (std::is_same_v<T, std::complex<float>>)
1217 tabulate_tensor =
reinterpret_cast<void (*)(
1218 T*,
const T*,
const T*,
1219 const typename scalar_value_type<T>::value_type*,
const int*,
1220 const unsigned char*)
>(e.tabulate_tensor_complex64);
1223 else if constexpr (std::is_same_v<T, double>)
1224 tabulate_tensor = e.tabulate_tensor_float64;
1225#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1226 else if constexpr (std::is_same_v<T, std::complex<double>>)
1228 tabulate_tensor =
reinterpret_cast<void (*)(
1229 T*,
const T*,
const T*,
1230 const typename scalar_value_type<T>::value_type*,
const int*,
1231 const unsigned char*)
>(e.tabulate_tensor_complex128);
1235 throw std::runtime_error(
"Type not supported.");
1237 assert(tabulate_tensor);
1238 return Expression(coefficients, constants, std::span<const U>(X), Xshape,
1239 tabulate_tensor, value_shape, argument_function_space);
1244template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
1246 const ufcx_expression& e,
1247 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
1249 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
1253 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
1254 std::vector<std::string> coefficient_names;
1255 for (
int i = 0; i < e.num_coefficients; ++i)
1256 coefficient_names.push_back(e.coefficient_names[i]);
1258 for (
const std::string& name : coefficient_names)
1260 if (
auto it = coefficients.find(name); it != coefficients.end())
1261 coeff_map.push_back(it->second);
1264 throw std::runtime_error(
"Expression coefficient \"" + name
1265 +
"\" not provided.");
1270 std::vector<std::shared_ptr<const Constant<T>>> const_map;
1271 std::vector<std::string> constant_names;
1272 for (
int i = 0; i < e.num_constants; ++i)
1273 constant_names.push_back(e.constant_names[i]);
1275 for (
const std::string& name : constant_names)
1277 if (
auto it = constants.find(name); it != constants.end())
1278 const_map.push_back(it->second);
1281 throw std::runtime_error(
"Expression constant \"" + name
1282 +
"\" not provided.");
1299template <dolfinx::scalar T, std::
floating_po
int U>
1301 std::map<std::pair<IntegralType, int>,
1302 std::pair<std::vector<T>,
int>>& coeffs)
1304 for (
auto& [key, val] : coeffs)
1316template <dolfinx::scalar T, std::
floating_po
int U>
1317std::pair<std::vector<T>,
int>
1319 std::span<const std::int32_t> entities, std::size_t estride)
1322 const std::vector<std::shared_ptr<const Function<T, U>>>& coeffs
1324 const std::vector<int> offsets = e.coefficient_offsets();
1327 const int cstride = offsets.back();
1328 std::vector<T> c(entities.size() / estride * offsets.back());
1329 if (!coeffs.empty())
1332 for (std::size_t coeff = 0; coeff < coeffs.size(); ++coeff)
1334 std::span<const std::uint32_t> cell_info
1335 = impl::get_cell_orientation_info(*coeffs[coeff]);
1337 impl::pack_coefficient_entity(
1338 std::span(c), cstride, *coeffs[coeff], cell_info, entities, estride,
1339 [](
auto entity) {
return entity[0]; }, offsets[coeff]);
1342 return {std::move(c), cstride};
1347template <
typename U>
1350 using T =
typename U::scalar_type;
1351 const std::vector<std::shared_ptr<const Constant<T>>>& constants
1355 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
1356 [](std::int32_t sum,
auto& constant)
1357 { return sum + constant->value.size(); });
1360 std::vector<T> constant_values(size);
1361 std::int32_t offset = 0;
1362 for (
auto& constant : constants)
1364 const std::vector<T>& value = constant->value;
1365 std::ranges::copy(value, std::next(constant_values.begin(), offset));
1366 offset += value.size();
1369 return constant_values;
Degree-of-freedom map representations and tools.
double stop()
Definition Timer.cpp:38
Constant value which can be attached to a Form.
Definition Form.h:29
Degree-of-freedom map.
Definition DofMap.h:76
std::span< const std::int32_t > cell_dofs(std::int32_t c) const
Local-to-global mapping of dofs on a cell.
Definition DofMap.h:130
int bs() const noexcept
Return the block size for the dofmap.
Definition DofMap.cpp:173
Definition ElementDofLayout.h:30
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell.
Definition Function.h:32
Model of a finite element.
Definition FiniteElement.h:38
This class represents a finite element function space defined by a mesh, a finite element,...
Definition vtk_utils.h:32
Definition topologycomputation.h:24
std::span< T > links(std::size_t node)
Definition AdjacencyList.h:111
Definition SparsityPattern.h:26
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:44
Concepts for function that returns cell index.
Definition utils.h:908
void pack(std::span< T > coeffs, std::int32_t cell, int bs, std::span< const T > v, std::span< const std::uint32_t > cell_info, const DofMap &dofmap, auto transform)
Pack a single coefficient for a single cell.
Definition utils.h:878
std::array< std::int32_t, 2 *num_cells > get_cell_facet_pairs(std::int32_t f, std::span< const std::int32_t > cells, const graph::AdjacencyList< std::int32_t > &c_to_f)
Definition utils.h:63
void pack_coefficient_entity(std::span< T > c, int cstride, const Function< T, U > &u, std::span< const std::uint32_t > cell_info, std::span< const std::int32_t > entities, std::size_t estride, FetchCells auto &&fetch_cells, std::int32_t offset)
Pack a single coefficient for a set of active entities.
Definition utils.h:927
Functions supporting mesh operations.
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
void interior_facets(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over interior facets and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:28
void cells(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:16
Finite element method functionality.
Definition assemble_matrix_impl.h:26
std::vector< std::string > get_constant_names(const ufcx_form &ufcx_form)
Get the name of each constant in a UFC form.
Definition utils.cpp:124
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T, U > &form, IntegralType integral_type, int id)
Allocate storage for coefficients of a pair (integral_type, / id) from a Form.
Definition utils.h:1008
Form< T, U > create_form_factory(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace< U > > > &spaces, const std::vector< std::shared_ptr< const Function< T, U > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, const std::map< IntegralType, std::vector< std::pair< std::int32_t, std::span< const std::int32_t > > > > &subdomains, const std::map< std::shared_ptr< const mesh::Mesh< U > >, std::span< const std::int32_t > > &entity_maps, std::shared_ptr< const mesh::Mesh< U > > mesh=nullptr)
Create a Form from UFCx input with coefficients and constants passed in the required order.
Definition utils.h:333
std::vector< DofMap > create_dofmaps(MPI_Comm comm, const std::vector< ElementDofLayout > &layouts, mesh::Topology &topology, std::function< void(std::span< std::int32_t >, std::uint32_t)> permute_inv, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn)
Create a set of dofmaps on a given topology.
Definition utils.cpp:68
DofMap create_dofmap(MPI_Comm comm, const ElementDofLayout &layout, mesh::Topology &topology, std::function< void(std::span< std::int32_t >, std::uint32_t)> permute_inv, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn)
Create a dof map on mesh.
Definition utils.cpp:31
std::vector< std::string > get_coefficient_names(const ufcx_form &ufcx_form)
Definition utils.cpp:117
FunctionSpace(U mesh, V element, W dofmap, X value_shape) -> FunctionSpace< typename std::remove_cvref< typename U::element_type >::type::geometry_type::value_type >
Type deduction.
std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace< U > >, 2 > > > extract_function_spaces(const std::vector< std::vector< const Form< T, U > * > > &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition utils.h:122
std::vector< std::int32_t > compute_integration_domains(IntegralType integral_type, const mesh::Topology &topology, std::span< const std::int32_t > entities, int dim)
Given an integral type and a set of entities, compute the entities that should be integrated over.
Definition utils.cpp:131
std::vector< typename U::scalar_type > pack_constants(const U &u)
Pack constants of u into a single array ready for assembly.
Definition utils.h:1348
Expression< T, U > create_expression(const ufcx_expression &e, const std::vector< std::shared_ptr< const Function< T, U > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, std::shared_ptr< const FunctionSpace< U > > argument_function_space=nullptr)
Create Expression from UFC.
Definition utils.h:1191
ElementDofLayout create_element_dof_layout(const fem::FiniteElement< T > &element, const std::vector< int > &parent_map={})
Create an ElementDofLayout from a FiniteElement.
Definition utils.h:241
Form< T, U > create_form(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace< U > > > &spaces, const std::map< std::string, std::shared_ptr< const Function< T, U > > > &coefficients, const std::map< std::string, std::shared_ptr< const Constant< T > > > &constants, const std::map< IntegralType, std::vector< std::pair< std::int32_t, std::span< const std::int32_t > > > > &subdomains, const std::map< std::shared_ptr< const mesh::Mesh< U > >, std::span< const std::int32_t > > &entity_maps, std::shared_ptr< const mesh::Mesh< U > > mesh=nullptr)
Create a Form from UFC input with coefficients and constants resolved by name.
Definition utils.h:703
IntegralType
Type of integral.
Definition Form.h:35
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
FunctionSpace< T > create_functionspace(std::shared_ptr< mesh::Mesh< T > > mesh, const basix::FiniteElement< T > &e, const std::vector< std::size_t > &value_shape={}, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
Create a function space from a Basix element.
Definition utils.h:796
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:147
std::vector< std::size_t > compute_value_shape(std::shared_ptr< const dolfinx::fem::FiniteElement< T > > element, std::size_t tdim, std::size_t gdim)
Compute the physical value shape of an element for a mesh.
Definition FunctionSpace.h:439
void pack_coefficients(const Form< T, U > &form, IntegralType integral_type, int id, std::span< T > c, int cstride)
Pack coefficients of a Form for a given integral type and domain id.
Definition utils.h:1062
CellType cell_type_from_basix_type(basix::cell::type celltype)
Get a cell type from a Basix cell type.
Definition cell_types.cpp:237
std::vector< std::int32_t > exterior_facet_indices(const Topology &topology)
Compute the indices of all exterior facets that are owned by the caller.
Definition utils.cpp:58