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>
43template <std::
floating_po
int T>
62template <
int num_cells>
63std::array<std::int32_t, 2 * num_cells>
68 assert(cells.size() == num_cells);
69 std::array<std::int32_t, 2 * num_cells> cell_local_facet_pairs;
70 for (
int c = 0; c < num_cells; ++c)
73 std::int32_t
cell = cells[c];
75 auto facet_it = std::find(cell_facets.begin(), cell_facets.end(), f);
76 assert(facet_it != cell_facets.end());
77 int local_f = std::distance(cell_facets.begin(), facet_it);
78 cell_local_facet_pairs[2 * c] =
cell;
79 cell_local_facet_pairs[2 * c + 1] = local_f;
82 return cell_local_facet_pairs;
113std::vector<std::int32_t>
116 std::span<const std::int32_t> entities);
125template <dolfinx::scalar T, std::
floating_po
int U>
126std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
130 std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
135 for (std::size_t i = 0; i < a.size(); ++i)
137 for (std::size_t j = 0; j < a[i].size(); ++j)
140 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
151template <dolfinx::scalar T, std::
floating_po
int U>
156 throw std::runtime_error(
157 "Cannot create sparsity pattern. Form is not a bilinear.");
161 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
162 *a.function_spaces().at(0)->dofmap(),
163 *a.function_spaces().at(1)->dofmap()};
164 std::shared_ptr mesh = a.mesh();
167 std::shared_ptr mesh0 = a.function_spaces().at(0)->mesh();
169 std::shared_ptr mesh1 = a.function_spaces().at(1)->mesh();
172 const std::set<IntegralType> types = a.integral_types();
177 int tdim = mesh->topology()->dim();
178 mesh->topology_mutable()->create_entities(tdim - 1);
179 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
185 const std::array index_maps{dofmaps[0].get().index_map,
186 dofmaps[1].get().index_map};
188 = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
190 auto extract_cells = [](std::span<const std::int32_t> facets)
192 assert(facets.size() % 2 == 0);
193 std::vector<std::int32_t> cells;
194 cells.reserve(facets.size() / 2);
195 for (std::size_t i = 0; i < facets.size(); i += 2)
196 cells.push_back(facets[i]);
202 for (
auto type : types)
204 std::vector<int> ids = a.integral_ids(type);
211 pattern, {a.domain(type,
id, *mesh0), a.domain(type,
id, *mesh1)},
212 {{dofmaps[0], dofmaps[1]}});
220 {extract_cells(a.domain(type,
id, *mesh0)),
221 extract_cells(a.domain(type,
id, *mesh1))},
222 {{dofmaps[0], dofmaps[1]}});
229 {extract_cells(a.domain(type,
id, *mesh0)),
230 extract_cells(a.domain(type,
id, *mesh1))},
231 {{dofmaps[0], dofmaps[1]}});
235 throw std::runtime_error(
"Unsupported integral type");
245template <std::
floating_po
int T>
247 const std::vector<int>& parent_map
251 std::vector<int> offsets(1, 0);
252 std::vector<dolfinx::fem::ElementDofLayout> sub_doflayout;
253 int bs = element.block_size();
254 for (
int i = 0; i < element.num_sub_elements(); ++i)
259 std::shared_ptr<const fem::FiniteElement<T>> sub_e
260 = element.sub_elements()[bs > 1 ? 0 : i];
266 std::vector<int> parent_map_sub(sub_e->space_dimension(), offsets.back());
267 for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
268 parent_map_sub[j] += bs * j;
269 offsets.push_back(offsets.back() + (bs > 1 ? 1 : sub_e->space_dimension()));
270 sub_doflayout.push_back(
274 return ElementDofLayout(bs, element.entity_dofs(),
275 element.entity_closure_dofs(), parent_map,
288 MPI_Comm comm,
const ElementDofLayout& layout,
mesh::Topology& topology,
289 std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
304 MPI_Comm comm,
const std::vector<ElementDofLayout>& layouts,
306 std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
338template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
340 const ufcx_form& ufcx_form,
342 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
343 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
346 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
349 std::span<const std::int32_t>>& entity_maps,
352 if (ufcx_form.rank != (
int)spaces.size())
353 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
354 if (ufcx_form.num_coefficients != (
int)coefficients.size())
356 throw std::runtime_error(
357 "Mismatch between number of expected and provided Form coefficients.");
359 if (ufcx_form.num_constants != (
int)constants.size())
361 throw std::runtime_error(
362 "Mismatch between number of expected and provided Form constants.");
366 for (std::size_t i = 0; i < spaces.size(); ++i)
368 assert(spaces[i]->element());
369 if (
auto element_hash = ufcx_form.finite_element_hashes[i];
371 and element_hash != spaces[i]->element()->basix_element().hash())
373 throw std::runtime_error(
"Cannot create form. Elements are different to "
374 "those used to compile the form.");
379 if (!mesh and !spaces.empty())
380 mesh = spaces[0]->mesh();
381 for (
auto& V : spaces)
383 if (mesh != V->mesh() and entity_maps.find(V->mesh()) == entity_maps.end())
384 throw std::runtime_error(
385 "Incompatible mesh. entity_maps must be provided.");
388 throw std::runtime_error(
"No mesh could be associated with the Form.");
390 auto topology = mesh->topology();
392 const int tdim = topology->
dim();
394 const int* integral_offsets = ufcx_form.form_integral_offsets;
395 std::vector<int> num_integrals_type(3);
396 for (
int i = 0; i < 3; ++i)
397 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
403 mesh->topology_mutable()->create_entities(tdim - 1);
404 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
405 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
410 using kern_t = std::function<void(T*,
const T*,
const T*,
const U*,
411 const int*,
const std::uint8_t*)>;
412 std::map<IntegralType, std::vector<integral_data<T, U>>> integrals;
415 bool needs_facet_permutations =
false;
416 std::vector<std::int32_t> default_cells;
418 std::span<const int> ids(ufcx_form.form_integral_ids
419 + integral_offsets[
cell],
420 num_integrals_type[
cell]);
423 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
425 const int id = ids[i];
426 ufcx_integral* integral
427 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
431 std::vector<int> active_coeffs;
432 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
434 if (integral->enabled_coefficients[j])
435 active_coeffs.push_back(j);
439 if constexpr (std::is_same_v<T, float>)
440 k = integral->tabulate_tensor_float32;
441#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
442 else if constexpr (std::is_same_v<T, std::complex<float>>)
444 k =
reinterpret_cast<void (*)(
445 T*,
const T*,
const T*,
446 const typename scalar_value_type<T>::value_type*,
const int*,
447 const unsigned char*)
>(integral->tabulate_tensor_complex64);
450 else if constexpr (std::is_same_v<T, double>)
451 k = integral->tabulate_tensor_float64;
452#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
453 else if constexpr (std::is_same_v<T, std::complex<double>>)
455 k =
reinterpret_cast<void (*)(
456 T*,
const T*,
const T*,
457 const typename scalar_value_type<T>::value_type*,
const int*,
458 const unsigned char*)
>(integral->tabulate_tensor_complex128);
464 throw std::runtime_error(
465 "UFCx kernel function is NULL. Check requested types.");
473 default_cells.resize(topology->
index_map(tdim)->size_local(), 0);
474 std::iota(default_cells.begin(), default_cells.end(), 0);
475 itg.first->second.emplace_back(
id, k, default_cells, active_coeffs);
477 else if (sd != subdomains.end())
481 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
482 [](
const auto& a) { return a.first; });
483 if (it != sd->second.end() and it->first ==
id)
484 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
487 if (integral->needs_facet_permutations)
488 needs_facet_permutations =
true;
493 std::vector<std::int32_t> default_facets_ext;
495 std::span<const int> ids(ufcx_form.form_integral_ids
502 const int id = ids[i];
503 ufcx_integral* integral
506 std::vector<int> active_coeffs;
507 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
509 if (integral->enabled_coefficients[j])
510 active_coeffs.push_back(j);
514 if constexpr (std::is_same_v<T, float>)
515 k = integral->tabulate_tensor_float32;
516#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
517 else if constexpr (std::is_same_v<T, std::complex<float>>)
519 k =
reinterpret_cast<void (*)(
520 T*,
const T*,
const T*,
521 const typename scalar_value_type<T>::value_type*,
const int*,
522 const unsigned char*)
>(integral->tabulate_tensor_complex64);
525 else if constexpr (std::is_same_v<T, double>)
526 k = integral->tabulate_tensor_float64;
527#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
528 else if constexpr (std::is_same_v<T, std::complex<double>>)
530 k =
reinterpret_cast<void (*)(
531 T*,
const T*,
const T*,
532 const typename scalar_value_type<T>::value_type*,
const int*,
533 const unsigned char*)
>(integral->tabulate_tensor_complex128);
547 default_facets_ext.reserve(2 * bfacets.size());
548 for (std::int32_t f : bfacets)
552 = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
553 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
556 itg.first->second.emplace_back(
id, k, default_facets_ext,
559 else if (sd != subdomains.end())
563 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
564 [](
const auto& a) { return a.first; });
565 if (it != sd->second.end() and it->first ==
id)
566 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
569 if (integral->needs_facet_permutations)
570 needs_facet_permutations =
true;
575 std::vector<std::int32_t> default_facets_int;
577 std::span<const int> ids(ufcx_form.form_integral_ids
584 std::vector<std::int8_t> interprocess_marker;
588 const std::vector<std::int32_t>& interprocess_facets
590 std::int32_t num_facets = topology->
index_map(tdim - 1)->size_local()
591 + topology->
index_map(tdim - 1)->num_ghosts();
592 interprocess_marker.resize(num_facets, 0);
593 std::ranges::for_each(interprocess_facets, [&interprocess_marker](
auto f)
594 { interprocess_marker[f] = 1; });
599 const int id = ids[i];
600 ufcx_integral* integral
603 std::vector<int> active_coeffs;
604 for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
606 if (integral->enabled_coefficients[j])
607 active_coeffs.push_back(j);
611 if constexpr (std::is_same_v<T, float>)
612 k = integral->tabulate_tensor_float32;
613#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
614 else if constexpr (std::is_same_v<T, std::complex<float>>)
616 k =
reinterpret_cast<void (*)(
617 T*,
const T*,
const T*,
618 const typename scalar_value_type<T>::value_type*,
const int*,
619 const unsigned char*)
>(integral->tabulate_tensor_complex64);
622 else if constexpr (std::is_same_v<T, double>)
623 k = integral->tabulate_tensor_float64;
624#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
625 else if constexpr (std::is_same_v<T, std::complex<double>>)
627 k =
reinterpret_cast<void (*)(
628 T*,
const T*,
const T*,
629 const typename scalar_value_type<T>::value_type*,
const int*,
630 const unsigned char*)
>(integral->tabulate_tensor_complex128);
644 std::int32_t num_facets = topology->
index_map(tdim - 1)->size_local();
645 default_facets_int.reserve(4 * num_facets);
646 for (std::int32_t f = 0; f < num_facets; ++f)
648 if (f_to_c->num_links(f) == 2)
651 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
652 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
655 else if (interprocess_marker[f])
657 throw std::runtime_error(
658 "Cannot compute interior facet integral over interprocess "
659 "facet. Please use ghost mode shared facet when creating the "
663 itg.first->second.emplace_back(
id, k, default_facets_int,
666 else if (sd != subdomains.end())
669 = std::ranges::lower_bound(sd->second,
id, std::less<>{},
670 [](
const auto& a) { return a.first; });
671 if (it != sd->second.end() and it->first ==
id)
672 itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
675 if (integral->needs_facet_permutations)
676 needs_facet_permutations =
true;
681 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>
683 for (
auto& [itg, data] : subdomains)
685 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>> x;
686 for (
auto& [
id, idx] : data)
687 x.emplace_back(
id, std::vector(idx.data(), idx.data() + idx.size()));
688 sd.insert({itg, std::move(x)});
691 return Form<T, U>(spaces, integrals, coefficients, constants,
692 needs_facet_permutations, entity_maps, mesh);
709template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
711 const ufcx_form& ufcx_form,
713 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
715 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
718 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
721 std::span<const std::int32_t>>& entity_maps,
725 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
728 if (
auto it = coefficients.find(name); it != coefficients.end())
729 coeff_map.push_back(it->second);
732 throw std::runtime_error(
"Form coefficient \"" + name
733 +
"\" not provided.");
738 std::vector<std::shared_ptr<const Constant<T>>> const_map;
741 if (
auto it = constants.find(name); it != constants.end())
742 const_map.push_back(it->second);
744 throw std::runtime_error(
"Form constant \"" + name +
"\" not provided.");
748 subdomains, entity_maps, mesh);
769template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
771 ufcx_form* (*fptr)(),
773 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
775 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
778 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
781 std::span<const std::int32_t>>& entity_maps,
784 ufcx_form* form = fptr();
786 subdomains, entity_maps, mesh);
792template <std::
floating_po
int T>
804 assert(mesh->topology());
805 if (e->cell_type() != mesh->topology()->cell_type())
806 throw std::runtime_error(
"Cell type of element and mesh must match.");
812 std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv
813 = e->needs_dof_permutations() ? e->dof_permutation_fn(
true,
true)
816 mesh->comm(), layout, *mesh->topology(), permute_inv, reorder_fn));
825template <dolfinx::scalar T, std::
floating_po
int U>
826std::span<const std::uint32_t>
827get_cell_orientation_info(
const Function<T, U>& coefficient)
829 std::span<const std::uint32_t> cell_info;
830 auto element = coefficient.function_space()->element();
831 if (element->needs_dof_transformations())
833 auto mesh = coefficient.function_space()->mesh();
834 mesh->topology_mutable()->create_entity_permutations();
835 cell_info = std::span(mesh->topology()->get_cell_permutation_info());
842template <
int _bs, dolfinx::scalar T>
843void pack(std::span<T> coeffs, std::int32_t
cell,
int bs, std::span<const T> v,
844 std::span<const std::uint32_t> cell_info,
const DofMap& dofmap,
848 for (std::size_t i = 0; i < dofs.size(); ++i)
850 if constexpr (_bs < 0)
852 const int pos_c = bs * i;
853 const int pos_v = bs * dofs[i];
854 for (
int k = 0; k < bs; ++k)
855 coeffs[pos_c + k] = v[pos_v + k];
860 const int pos_c = _bs * i;
861 const int pos_v = _bs * dofs[i];
862 for (
int k = 0; k < _bs; ++k)
863 coeffs[pos_c + k] = v[pos_v + k];
867 transform(coeffs, cell_info,
cell, 1);
873concept FetchCells =
requires(F&& f, std::span<const std::int32_t> v) {
874 requires std::invocable<F, std::span<const std::int32_t>>;
875 { f(v) } -> std::convertible_to<std::int32_t>;
891template <dolfinx::scalar T, std::
floating_po
int U>
894 std::span<const std::uint32_t> cell_info,
895 std::span<const std::int32_t> entities,
896 std::size_t estride,
FetchCells auto&& fetch_cells,
900 std::span<const T> v = u.x()->array();
901 const DofMap& dofmap = *u.function_space()->dofmap();
902 auto element = u.function_space()->element();
904 int space_dim = element->space_dimension();
910 const int bs = dofmap.
bs();
914 for (std::size_t e = 0; e < entities.size(); e += estride)
916 auto entity = entities.subspan(e, estride);
917 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
920 = c.subspan((e / estride) * cstride + offset, space_dim);
921 pack<1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
926 for (std::size_t e = 0; e < entities.size(); e += estride)
928 auto entity = entities.subspan(e, estride);
929 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
932 = c.subspan((e / estride) * cstride + offset, space_dim);
933 pack<2>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
938 for (std::size_t e = 0; e < entities.size(); e += estride)
940 auto entity = entities.subspan(e, estride);
941 if (std::int32_t
cell = fetch_cells(entity);
cell >= 0)
943 auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
944 pack<3>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
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);
971template <dolfinx::scalar T, std::
floating_po
int U>
972std::pair<std::vector<T>,
int>
977 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
981 std::size_t num_entities = 0;
983 if (!coefficients.empty())
985 cstride = offsets.back();
986 num_entities = form.
domain(integral_type,
id).size();
994 return {std::vector<T>(num_entities * cstride), cstride};
1001template <dolfinx::scalar T, std::
floating_po
int U>
1002std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>>
1005 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>> coeffs;
1010 coeffs.emplace_hint(
1011 coeffs.end(), std::pair(integral_type,
id),
1026template <dolfinx::scalar T, std::
floating_po
int U>
1028 int id, std::span<T> c,
int cstride)
1031 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
1036 std::vector<int> active_coefficient(coefficients.size(), 0);
1037 if (!coefficients.empty())
1039 switch (integral_type)
1048 active_coefficient[idx] = 1;
1052 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1054 if (!active_coefficient[coeff])
1058 auto mesh = coefficients[coeff]->function_space()->mesh();
1065 = form.
mesh()->topology()->dim() - mesh->topology()->dim();
1068 throw std::runtime_error(
"Should not be packing coefficients with "
1069 "codim>0 in a cell integral");
1072 std::vector<std::int32_t> cells
1074 std::span<const std::uint32_t> cell_info
1075 = impl::get_cell_orientation_info(*coefficients[coeff]);
1076 impl::pack_coefficient_entity(
1077 c, cstride, *coefficients[coeff], cell_info, cells, 1,
1078 [](
auto entity) {
return entity.front(); }, offsets[coeff]);
1086 for (std::size_t i = 0;
1090 active_coefficient[idx] = 1;
1094 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1096 if (!active_coefficient[coeff])
1099 auto mesh = coefficients[coeff]->function_space()->mesh();
1100 std::vector<std::int32_t> facets
1102 std::span<const std::uint32_t> cell_info
1103 = impl::get_cell_orientation_info(*coefficients[coeff]);
1104 impl::pack_coefficient_entity(
1105 c, cstride, *coefficients[coeff], cell_info, facets, 2,
1106 [](
auto entity) {
return entity.front(); }, offsets[coeff]);
1114 for (std::size_t i = 0;
1118 active_coefficient[idx] = 1;
1122 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1124 if (!active_coefficient[coeff])
1127 auto mesh = coefficients[coeff]->function_space()->mesh();
1128 std::vector<std::int32_t> facets
1131 std::span<const std::uint32_t> cell_info
1132 = impl::get_cell_orientation_info(*coefficients[coeff]);
1135 impl::pack_coefficient_entity(
1136 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1137 [](
auto entity) {
return entity[0]; }, 2 * offsets[coeff]);
1140 impl::pack_coefficient_entity(
1141 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1142 [](
auto entity) {
return entity[2]; },
1143 offsets[coeff] + offsets[coeff + 1]);
1148 throw std::runtime_error(
1149 "Could not pack coefficient. Integral type not supported.");
1155template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
1157 const ufcx_expression& e,
1158 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
1159 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
1162 if (e.rank > 0 and !argument_function_space)
1164 throw std::runtime_error(
"Expression has Argument but no Argument "
1165 "function space was provided.");
1168 std::vector<U> X(e.points, e.points + e.num_points * e.entity_dimension);
1169 std::array<std::size_t, 2> Xshape
1170 = {
static_cast<std::size_t
>(e.num_points),
1171 static_cast<std::size_t
>(e.entity_dimension)};
1172 std::vector<std::size_t> value_shape(e.value_shape,
1173 e.value_shape + e.num_components);
1174 std::function<void(T*,
const T*,
const T*,
1175 const typename scalar_value_type<T>::value_type*,
1176 const int*,
const std::uint8_t*)>
1177 tabulate_tensor =
nullptr;
1178 if constexpr (std::is_same_v<T, float>)
1179 tabulate_tensor = e.tabulate_tensor_float32;
1180#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1181 else if constexpr (std::is_same_v<T, std::complex<float>>)
1183 tabulate_tensor =
reinterpret_cast<void (*)(
1184 T*,
const T*,
const T*,
1185 const typename scalar_value_type<T>::value_type*,
const int*,
1186 const unsigned char*)
>(e.tabulate_tensor_complex64);
1189 else if constexpr (std::is_same_v<T, double>)
1190 tabulate_tensor = e.tabulate_tensor_float64;
1191#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1192 else if constexpr (std::is_same_v<T, std::complex<double>>)
1194 tabulate_tensor =
reinterpret_cast<void (*)(
1195 T*,
const T*,
const T*,
1196 const typename scalar_value_type<T>::value_type*,
const int*,
1197 const unsigned char*)
>(e.tabulate_tensor_complex128);
1201 throw std::runtime_error(
"Type not supported.");
1203 assert(tabulate_tensor);
1204 return Expression(coefficients, constants, std::span<const U>(X), Xshape,
1205 tabulate_tensor, value_shape, argument_function_space);
1210template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
1212 const ufcx_expression& e,
1213 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
1215 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
1219 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
1220 std::vector<std::string> coefficient_names;
1221 for (
int i = 0; i < e.num_coefficients; ++i)
1222 coefficient_names.push_back(e.coefficient_names[i]);
1224 for (
const std::string& name : coefficient_names)
1226 if (
auto it = coefficients.find(name); it != coefficients.end())
1227 coeff_map.push_back(it->second);
1230 throw std::runtime_error(
"Expression coefficient \"" + name
1231 +
"\" not provided.");
1236 std::vector<std::shared_ptr<const Constant<T>>> const_map;
1237 std::vector<std::string> constant_names;
1238 for (
int i = 0; i < e.num_constants; ++i)
1239 constant_names.push_back(e.constant_names[i]);
1241 for (
const std::string& name : constant_names)
1243 if (
auto it = constants.find(name); it != constants.end())
1244 const_map.push_back(it->second);
1247 throw std::runtime_error(
"Expression constant \"" + name
1248 +
"\" not provided.");
1265template <dolfinx::scalar T, std::
floating_po
int U>
1267 std::map<std::pair<IntegralType, int>,
1268 std::pair<std::vector<T>,
int>>& coeffs)
1270 for (
auto& [key, val] : coeffs)
1282template <dolfinx::scalar T, std::
floating_po
int U>
1283std::pair<std::vector<T>,
int>
1285 std::span<const std::int32_t> entities, std::size_t estride)
1288 const std::vector<std::shared_ptr<const Function<T, U>>>& coeffs
1290 const std::vector<int> offsets = e.coefficient_offsets();
1293 const int cstride = offsets.back();
1294 std::vector<T> c(entities.size() / estride * offsets.back());
1295 if (!coeffs.empty())
1298 for (std::size_t coeff = 0; coeff < coeffs.size(); ++coeff)
1300 std::span<const std::uint32_t> cell_info
1301 = impl::get_cell_orientation_info(*coeffs[coeff]);
1303 impl::pack_coefficient_entity(
1304 std::span(c), cstride, *coeffs[coeff], cell_info, entities, estride,
1305 [](
auto entity) {
return entity[0]; }, offsets[coeff]);
1308 return {std::move(c), cstride};
1313template <
typename U>
1316 using T =
typename U::scalar_type;
1317 const std::vector<std::shared_ptr<const Constant<T>>>& constants
1321 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
1322 [](std::int32_t sum,
auto& constant)
1323 { return sum + constant->value.size(); });
1326 std::vector<T> constant_values(size);
1327 std::int32_t offset = 0;
1328 for (
auto& constant : constants)
1330 const std::vector<T>& value = constant->value;
1331 std::ranges::copy(value, std::next(constant_values.begin(), offset));
1332 offset += value.size();
1335 return constant_values;
Degree-of-freedom map representations and tools.
Timer for measuring and logging elapsed time durations.
Definition Timer.h:41
std::chrono::duration< double, Period > stop()
Stop timer and return elapsed time.
Definition Timer.h:91
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:57
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:45
std::shared_ptr< const common::IndexMap > index_map(int dim) const
Get the IndexMap that described the parallel distribution of the mesh entities.
Definition Topology.cpp:821
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(int d0, int d1) const
Return connectivity from entities of dimension d0 to entities of dimension d1. Assumes only one entit...
Definition Topology.cpp:937
const std::vector< std::int32_t > & interprocess_facets() const
List of inter-process facets.
Definition Topology.cpp:1015
int dim() const noexcept
Return the topological dimension of the mesh.
Definition Topology.cpp:800
Concepts for function that returns cell index.
Definition utils.h:873
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:843
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:64
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:892
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:973
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:339
FunctionSpace< T > create_functionspace(std::shared_ptr< mesh::Mesh< T > > mesh, std::shared_ptr< const fem::FiniteElement< T > > e, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
NEW Create a function space from a fem::FiniteElement.
Definition utils.h:793
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
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:127
std::vector< std::int32_t > compute_integration_domains(IntegralType integral_type, const mesh::Topology &topology, std::span< const std::int32_t > entities)
Given an integral type and a set of entities, computes and return data for the entities that should b...
Definition utils.cpp:132
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:1314
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:1156
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:246
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:710
IntegralType
Type of integral.
Definition Form.h:35
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:152
FunctionSpace(U mesh, V element, W dofmap) -> FunctionSpace< typename std::remove_cvref< typename U::element_type >::type::geometry_type::value_type >
Type deduction.
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:1027
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