10#include "CoordinateElement.h"
12#include "ElementDofLayout.h"
13#include "Expression.h"
16#include "FunctionSpace.h"
17#include "sparsitybuild.h"
20#include <dolfinx/common/types.h>
21#include <dolfinx/la/SparsityPattern.h>
22#include <dolfinx/mesh/Topology.h>
23#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;
111std::vector<std::pair<int, std::vector<std::int32_t>>>
114 std::span<const std::int32_t> entities,
int dim,
115 std::span<const int> values);
121template <
class U,
class T>
122concept FEkernel = std::is_invocable_v<U, T*,
const T*,
const T*,
123 const scalar_value_type_t<T>*,
124 const int*,
const std::uint8_t*>;
133template <dolfinx::scalar T, std::
floating_po
int U>
134std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
138 std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
143 for (std::size_t i = 0; i < a.size(); ++i)
145 for (std::size_t j = 0; j < a[i].size(); ++j)
148 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
159template <dolfinx::scalar T, std::
floating_po
int U>
164 throw std::runtime_error(
165 "Cannot create sparsity pattern. Form is not a bilinear.");
169 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
172 std::shared_ptr mesh = a.
mesh();
180 int tdim = mesh->topology()->dim();
181 mesh->topology_mutable()->create_entities(tdim - 1);
182 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
188 const std::array index_maps{dofmaps[0].get().index_map,
189 dofmaps[1].get().index_map};
191 = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
195 for (
auto type : types)
204 {{dofmaps[0], dofmaps[1]}});
210 std::span<const std::int32_t> facets = a.
domain(type,
id);
211 std::vector<std::int32_t> f;
212 f.reserve(facets.size() / 2);
213 for (std::size_t i = 0; i < facets.size(); i += 4)
214 f.insert(f.end(), {facets[i], facets[i + 2]});
221 std::span<const std::int32_t> facets = a.
domain(type,
id);
222 std::vector<std::int32_t> cells;
223 cells.reserve(facets.size() / 2);
224 for (std::size_t i = 0; i < facets.size(); i += 2)
225 cells.push_back(facets[i]);
230 throw std::runtime_error(
"Unsupported integral type");
240ElementDofLayout create_element_dof_layout(
const ufcx_dofmap& dofmap,
241 const mesh::CellType cell_type,
242 const std::vector<int>& parent_map
254 MPI_Comm comm,
const ElementDofLayout& layout, mesh::Topology& topology,
255 std::function<
void(
const std::span<std::int32_t>&, std::uint32_t)>
257 std::function<std::vector<int>(
const graph::AdjacencyList<std::int32_t>&)>
278template <dolfinx::scalar T,
typename U = dolfinx::scalar_value_type_t<T>>
280 const ufcx_form& ufcx_form,
282 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
283 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
286 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
290 if (ufcx_form.rank != (
int)spaces.size())
291 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
292 if (ufcx_form.num_coefficients != (
int)coefficients.size())
294 throw std::runtime_error(
295 "Mismatch between number of expected and provided Form coefficients.");
297 if (ufcx_form.num_constants != (
int)constants.size())
299 throw std::runtime_error(
300 "Mismatch between number of expected and provided Form constants.");
305 for (std::size_t i = 0; i < spaces.size(); ++i)
307 assert(spaces[i]->element());
308 ufcx_finite_element* ufcx_element = ufcx_form.finite_elements[i];
309 assert(ufcx_element);
310 if (std::string(ufcx_element->signature)
311 != spaces[i]->element()->signature())
313 throw std::runtime_error(
314 "Cannot create form. Wrong type of function space for argument.");
320 if (!mesh and !spaces.empty())
321 mesh = spaces[0]->mesh();
322 for (
auto& V : spaces)
324 if (mesh != V->mesh())
325 throw std::runtime_error(
"Incompatible mesh");
328 throw std::runtime_error(
"No mesh could be associated with the Form.");
330 auto topology = mesh->topology();
332 const int tdim = topology->dim();
334 const int* integral_offsets = ufcx_form.form_integral_offsets;
335 std::vector<int> num_integrals_type(3);
336 for (
int i = 0; i < 3; ++i)
337 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
343 mesh->topology_mutable()->create_entities(tdim - 1);
344 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
345 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
350 using kern = std::function<void(
351 T*,
const T*,
const T*,
const typename scalar_value_type<T>::value_type*,
352 const int*,
const std::uint8_t*)>;
354 std::vector<std::tuple<int, kern, std::vector<std::int32_t>>>>
357 bool needs_facet_permutations =
false;
361 std::span<const int> ids(ufcx_form.form_integral_ids
362 + integral_offsets[
cell],
363 num_integrals_type[
cell]);
364 auto itg = integral_data.insert({IntegralType::cell, {}});
365 auto sd = subdomains.find(IntegralType::cell);
366 for (
int i = 0; i < num_integrals_type[
cell]; ++i)
368 const int id = ids[i];
369 ufcx_integral* integral
370 = ufcx_form.form_integrals[integral_offsets[
cell] + i];
374 if constexpr (std::is_same_v<T, float>)
375 k = integral->tabulate_tensor_float32;
376 else if constexpr (std::is_same_v<T, std::complex<float>>)
378 k =
reinterpret_cast<void (*)(
379 T*,
const T*,
const T*,
380 const typename scalar_value_type<T>::value_type*,
const int*,
381 const unsigned char*)
>(integral->tabulate_tensor_complex64);
383 else if constexpr (std::is_same_v<T, double>)
384 k = integral->tabulate_tensor_float64;
385 else if constexpr (std::is_same_v<T, std::complex<double>>)
387 k =
reinterpret_cast<void (*)(
388 T*,
const T*,
const T*,
389 const typename scalar_value_type<T>::value_type*,
const int*,
390 const unsigned char*)
>(integral->tabulate_tensor_complex128);
398 assert(topology->index_map(tdim));
399 std::vector<std::int32_t> e;
400 e.resize(topology->index_map(tdim)->size_local(), 0);
401 std::iota(e.begin(), e.end(), 0);
402 itg.first->second.emplace_back(
id, k, std::move(e));
404 else if (sd != subdomains.end())
407 auto it = std::lower_bound(sd->second.begin(), sd->second.end(),
id,
408 [](
auto& pair,
auto val)
409 { return pair.first < val; });
410 if (it != sd->second.end() and it->first ==
id)
411 itg.first->second.emplace_back(
id, k, it->second);
414 if (integral->needs_facet_permutations)
415 needs_facet_permutations =
true;
421 std::span<const int> ids(ufcx_form.form_integral_ids
424 auto itg = integral_data.insert({IntegralType::exterior_facet, {}});
425 auto sd = subdomains.find(IntegralType::exterior_facet);
428 const int id = ids[i];
429 ufcx_integral* integral
434 if constexpr (std::is_same_v<T, float>)
435 k = integral->tabulate_tensor_float32;
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);
443 else if constexpr (std::is_same_v<T, double>)
444 k = integral->tabulate_tensor_float64;
445 else if constexpr (std::is_same_v<T, std::complex<double>>)
447 k =
reinterpret_cast<void (*)(
448 T*,
const T*,
const T*,
449 const typename scalar_value_type<T>::value_type*,
const int*,
450 const unsigned char*)
>(integral->tabulate_tensor_complex128);
455 const std::vector bfacets = mesh::exterior_facet_indices(*topology);
456 auto f_to_c = topology->connectivity(tdim - 1, tdim);
458 auto c_to_f = topology->connectivity(tdim, tdim - 1);
463 std::vector<std::int32_t> e;
464 e.reserve(2 * bfacets.size());
465 for (std::int32_t f : bfacets)
469 = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
470 e.insert(e.end(), pair.begin(), pair.end());
472 itg.first->second.emplace_back(
id, k, std::move(e));
474 else if (sd != subdomains.end())
477 auto it = std::lower_bound(sd->second.begin(), sd->second.end(),
id,
478 [](
auto& pair,
auto val)
479 { return pair.first < val; });
480 if (it != sd->second.end() and it->first ==
id)
481 itg.first->second.emplace_back(
id, k, it->second);
484 if (integral->needs_facet_permutations)
485 needs_facet_permutations =
true;
491 std::span<const int> ids(ufcx_form.form_integral_ids
494 auto itg = integral_data.insert({IntegralType::interior_facet, {}});
495 auto sd = subdomains.find(IntegralType::interior_facet);
498 const int id = ids[i];
499 ufcx_integral* integral
504 if constexpr (std::is_same_v<T, float>)
505 k = integral->tabulate_tensor_float32;
506 else if constexpr (std::is_same_v<T, std::complex<float>>)
508 k =
reinterpret_cast<void (*)(
509 T*,
const T*,
const T*,
510 const typename scalar_value_type<T>::value_type*,
const int*,
511 const unsigned char*)
>(integral->tabulate_tensor_complex64);
513 else if constexpr (std::is_same_v<T, double>)
514 k = integral->tabulate_tensor_float64;
515 else if constexpr (std::is_same_v<T, std::complex<double>>)
517 k =
reinterpret_cast<void (*)(
518 T*,
const T*,
const T*,
519 const typename scalar_value_type<T>::value_type*,
const int*,
520 const unsigned char*)
>(integral->tabulate_tensor_complex128);
525 auto f_to_c = topology->connectivity(tdim - 1, tdim);
527 auto c_to_f = topology->connectivity(tdim, tdim - 1);
532 std::vector<std::int32_t> e;
533 assert(topology->index_map(tdim - 1));
534 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
535 e.reserve(4 * num_facets);
536 for (std::int32_t f = 0; f < num_facets; ++f)
538 if (f_to_c->num_links(f) == 2)
541 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
542 e.insert(e.end(), pairs.begin(), pairs.end());
545 itg.first->second.emplace_back(
id, k, std::move(e));
547 else if (sd != subdomains.end())
549 auto it = std::lower_bound(sd->second.begin(), sd->second.end(),
id,
550 [](
auto& pair,
auto val)
551 { return pair.first < val; });
552 if (it != sd->second.end() and it->first ==
id)
553 itg.first->second.emplace_back(
id, k, it->second);
556 if (integral->needs_facet_permutations)
557 needs_facet_permutations =
true;
562 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>
564 for (
auto& [itg, data] : subdomains)
566 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>> x;
567 for (
auto& [
id, idx] : data)
568 x.emplace_back(
id, std::vector(idx.data(), idx.data() + idx.size()));
569 sd.insert({itg, std::move(x)});
572 return Form<T, U>(spaces, integral_data, coefficients, constants,
573 needs_facet_permutations, mesh);
586template <dolfinx::scalar T,
typename U = dolfinx::scalar_value_type_t<T>>
588 const ufcx_form& ufcx_form,
590 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
592 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
595 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
600 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
603 if (
auto it = coefficients.find(name); it != coefficients.end())
604 coeff_map.push_back(it->second);
607 throw std::runtime_error(
"Form coefficient \"" + name
608 +
"\" not provided.");
613 std::vector<std::shared_ptr<const Constant<T>>> const_map;
616 if (
auto it = constants.find(name); it != constants.end())
617 const_map.push_back(it->second);
619 throw std::runtime_error(
"Form constant \"" + name +
"\" not provided.");
622 return create_form(ufcx_form, spaces, coeff_map, const_map, subdomains, mesh);
637template <dolfinx::scalar T,
typename U = dolfinx::scalar_value_type_t<T>>
639 ufcx_form* (*fptr)(),
641 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
643 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
646 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
650 ufcx_form* form = fptr();
651 Form<T, U> L = create_form<T, U>(*form, spaces, coefficients, constants,
668template <std::
floating_po
int T>
671 const std::vector<std::size_t>& value_shape = {},
677 auto _e = std::make_shared<FiniteElement<T>>(e, value_shape);
681 const int num_sub_elements = _e->num_sub_elements();
682 std::vector<ElementDofLayout> sub_doflayout;
683 sub_doflayout.reserve(num_sub_elements);
684 for (
int i = 0; i < num_sub_elements; ++i)
686 auto sub_element = _e->extract_sub_element({i});
687 std::vector<int> parent_map_sub(sub_element->space_dimension());
688 for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
689 parent_map_sub[j] = i + _e->block_size() * j;
690 sub_doflayout.emplace_back(1, e.entity_dofs(), e.entity_closure_dofs(),
691 parent_map_sub, std::vector<ElementDofLayout>());
695 ElementDofLayout layout(_e->block_size(), e.entity_dofs(),
696 e.entity_closure_dofs(), {}, sub_doflayout);
697 std::function<void(
const std::span<std::int32_t>&, std::uint32_t)>
698 unpermute_dofs =
nullptr;
699 if (_e->needs_dof_permutations())
700 unpermute_dofs = _e->get_dof_permutation_function(
true,
true);
702 assert(mesh->topology());
704 mesh->comm(), layout, *mesh->topology(), unpermute_dofs, reorder_fn));
718template <std::
floating_po
int T>
720 ufcx_function_space* (*fptr)(
const char*),
const std::string& function_name,
726 ufcx_function_space* space = fptr(function_name.c_str());
729 throw std::runtime_error(
730 "Could not create UFC function space with function name "
734 ufcx_finite_element* ufcx_element = space->finite_element;
735 assert(ufcx_element);
737 const auto& geometry = mesh->geometry();
738 if (geometry.cmaps().size() > 1)
739 throw std::runtime_error(
"Not supported for Mixed Topology");
741 const auto& cmap = geometry.cmaps()[0];
742 if (space->geometry_degree != cmap.degree()
743 or
static_cast<basix::cell::type
>(space->geometry_basix_cell)
744 != mesh::cell_type_to_basix_type(cmap.cell_shape())
745 or
static_cast<basix::element::lagrange_variant
>(
746 space->geometry_basix_variant)
749 throw std::runtime_error(
"UFL mesh and CoordinateElement do not match.");
752 auto element = std::make_shared<FiniteElement<T>>(*ufcx_element);
754 ufcx_dofmap* ufcx_map = space->dofmap;
756 const auto topology = mesh->topology();
761 std::function<void(
const std::span<std::int32_t>&, std::uint32_t)>
763 if (element->needs_dof_permutations())
764 unpermute_dofs = element->get_dof_permutation_function(
true,
true);
767 std::make_shared<DofMap>(
create_dofmap(mesh->comm(), layout, *topology,
768 unpermute_dofs, reorder_fn)));
775template <dolfinx::scalar T, std::
floating_po
int U>
776std::span<const std::uint32_t> get_cell_orientation_info(
777 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients)
779 bool needs_dof_transformations =
false;
780 for (
auto coeff : coefficients)
782 auto element = coeff->function_space()->element();
783 if (element->needs_dof_transformations())
785 needs_dof_transformations =
true;
790 std::span<const std::uint32_t> cell_info;
791 if (needs_dof_transformations)
793 auto mesh = coefficients.front()->function_space()->mesh();
794 mesh->topology_mutable()->create_entity_permutations();
795 cell_info = std::span(mesh->topology()->get_cell_permutation_info());
802template <dolfinx::scalar T,
int _bs>
803void pack(std::span<T> coeffs, std::int32_t cell,
int bs, std::span<const T> v,
804 std::span<const std::uint32_t> cell_info,
const DofMap& dofmap,
808 for (std::size_t i = 0; i < dofs.size(); ++i)
810 if constexpr (_bs < 0)
812 const int pos_c = bs * i;
813 const int pos_v = bs * dofs[i];
814 for (
int k = 0; k < bs; ++k)
815 coeffs[pos_c + k] = v[pos_v + k];
819 const int pos_c = _bs * i;
820 const int pos_v = _bs * dofs[i];
821 for (
int k = 0; k < _bs; ++k)
822 coeffs[pos_c + k] = v[pos_v + k];
826 transform(coeffs, cell_info,
cell, 1);
832concept FetchCells =
requires(F&& f, std::span<const std::int32_t> v) {
833 requires std::invocable<F, std::span<const std::int32_t>>;
836 } -> std::convertible_to<std::int32_t>;
852template <dolfinx::scalar T, std::
floating_po
int U>
855 std::span<const std::uint32_t> cell_info,
856 std::span<const std::int32_t> entities,
857 std::size_t estride,
FetchCells auto&& fetch_cells,
861 std::span<const T> v = u.
x()->array();
865 int space_dim = element->space_dimension();
867 = element->template get_dof_transformation_function<T>(
false,
true);
868 const int bs = dofmap.
bs();
872 for (std::size_t e = 0; e < entities.size(); e += estride)
874 auto entity = entities.subspan(e, estride);
875 std::int32_t
cell = fetch_cells(entity);
876 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
877 pack<T, 1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
881 for (std::size_t e = 0; e < entities.size(); e += estride)
883 auto entity = entities.subspan(e, estride);
884 std::int32_t
cell = fetch_cells(entity);
885 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
886 pack<T, 2>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
890 for (std::size_t e = 0; e < entities.size(); e += estride)
892 auto entity = entities.subspan(e, estride);
893 std::int32_t
cell = fetch_cells(entity);
894 auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
895 pack<T, 3>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
899 for (std::size_t e = 0; e < entities.size(); e += estride)
901 auto entity = entities.subspan(e, estride);
902 std::int32_t
cell = fetch_cells(entity);
903 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
904 pack<T, -1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
918template <dolfinx::scalar T, std::
floating_po
int U>
919std::pair<std::vector<T>,
int>
924 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
928 std::size_t num_entities = 0;
930 if (!coefficients.empty())
932 cstride = offsets.back();
933 num_entities = form.
domain(integral_type,
id).size();
934 if (integral_type == IntegralType::exterior_facet
935 or integral_type == IntegralType::interior_facet)
941 return {std::vector<T>(num_entities * cstride), cstride};
948template <dolfinx::scalar T, std::
floating_po
int U>
949std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>>
952 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>> coeffs;
958 coeffs.end(), std::pair(integral_type,
id),
973template <dolfinx::scalar T, std::
floating_po
int U>
975 int id, std::span<T> c,
int cstride)
978 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
982 if (!coefficients.empty())
984 std::span<const std::uint32_t> cell_info
985 = impl::get_cell_orientation_info(coefficients);
987 switch (integral_type)
989 case IntegralType::cell:
991 auto fetch_cell = [](
auto entity) {
return entity.front(); };
994 std::span<const std::int32_t> cells = form.
domain(IntegralType::cell,
id);
995 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
997 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
998 cell_info, cells, 1, fetch_cell,
1003 case IntegralType::exterior_facet:
1006 auto fetch_cell = [](
auto entity) {
return entity.front(); };
1009 std::span<const std::int32_t> facets
1010 = form.
domain(IntegralType::exterior_facet,
id);
1011 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1013 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
1014 cell_info, facets, 2, fetch_cell,
1019 case IntegralType::interior_facet:
1022 auto fetch_cell0 = [](
auto entity) {
return entity[0]; };
1023 auto fetch_cell1 = [](
auto entity) {
return entity[2]; };
1026 std::span<const std::int32_t> facets
1027 = form.
domain(IntegralType::interior_facet,
id);
1028 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1031 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
1032 cell_info, facets, 4, fetch_cell0,
1033 2 * offsets[coeff]);
1035 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
1036 cell_info, facets, 4, fetch_cell1,
1037 offsets[coeff] + offsets[coeff + 1]);
1042 throw std::runtime_error(
1043 "Could not pack coefficient. Integral type not supported.");
1049template <dolfinx::scalar T,
typename U = dolfinx::scalar_value_type_t<T>>
1051 const ufcx_expression& e,
1052 const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
1053 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
1056 if (e.rank > 0 and !argument_function_space)
1058 throw std::runtime_error(
"Expression has Argument but no Argument "
1059 "function space was provided.");
1062 std::vector<U> X(e.points, e.points + e.num_points * e.topological_dimension);
1063 std::array<std::size_t, 2> Xshape
1064 = {
static_cast<std::size_t
>(e.num_points),
1065 static_cast<std::size_t
>(e.topological_dimension)};
1066 std::vector<int> value_shape(e.value_shape, e.value_shape + e.num_components);
1067 std::function<void(T*,
const T*,
const T*,
1068 const typename scalar_value_type<T>::value_type*,
1069 const int*,
const std::uint8_t*)>
1070 tabulate_tensor =
nullptr;
1071 if constexpr (std::is_same_v<T, float>)
1072 tabulate_tensor = e.tabulate_tensor_float32;
1073 else if constexpr (std::is_same_v<T, std::complex<float>>)
1075 tabulate_tensor =
reinterpret_cast<void (*)(
1076 T*,
const T*,
const T*,
1077 const typename scalar_value_type<T>::value_type*,
const int*,
1078 const unsigned char*)
>(e.tabulate_tensor_complex64);
1080 else if constexpr (std::is_same_v<T, double>)
1081 tabulate_tensor = e.tabulate_tensor_float64;
1082 else if constexpr (std::is_same_v<T, std::complex<double>>)
1084 tabulate_tensor =
reinterpret_cast<void (*)(
1085 T*,
const T*,
const T*,
1086 const typename scalar_value_type<T>::value_type*,
const int*,
1087 const unsigned char*)
>(e.tabulate_tensor_complex128);
1090 throw std::runtime_error(
"Type not supported.");
1092 assert(tabulate_tensor);
1093 return Expression(coefficients, constants, std::span<const U>(X), Xshape,
1094 tabulate_tensor, value_shape, argument_function_space);
1099template <dolfinx::scalar T,
typename U = dolfinx::scalar_value_type_t<T>>
1101 const ufcx_expression& e,
1102 const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
1104 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
1108 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
1109 std::vector<std::string> coefficient_names;
1110 for (
int i = 0; i < e.num_coefficients; ++i)
1111 coefficient_names.push_back(e.coefficient_names[i]);
1113 for (
const std::string& name : coefficient_names)
1115 if (
auto it = coefficients.find(name); it != coefficients.end())
1116 coeff_map.push_back(it->second);
1119 throw std::runtime_error(
"Expression coefficient \"" + name
1120 +
"\" not provided.");
1125 std::vector<std::shared_ptr<const Constant<T>>> const_map;
1126 std::vector<std::string> constant_names;
1127 for (
int i = 0; i < e.num_constants; ++i)
1128 constant_names.push_back(e.constant_names[i]);
1130 for (
const std::string& name : constant_names)
1132 if (
auto it = constants.find(name); it != constants.end())
1133 const_map.push_back(it->second);
1136 throw std::runtime_error(
"Expression constant \"" + name
1137 +
"\" not provided.");
1149template <dolfinx::scalar T, std::
floating_po
int U>
1151 std::map<std::pair<IntegralType, int>,
1152 std::pair<std::vector<T>,
int>>& coeffs)
1154 for (
auto& [key, val] : coeffs)
1155 pack_coefficients<T>(form, key.first, key.second, val.first, val.second);
1164template <dolfinx::scalar T, std::
floating_po
int U>
1165std::pair<std::vector<T>,
int>
1167 std::span<const std::int32_t> cells)
1170 const std::vector<std::shared_ptr<const Function<T, U>>>& coeffs
1175 const int cstride = offsets.back();
1176 std::vector<T> c(cells.size() * offsets.back());
1177 if (!coeffs.empty())
1179 std::span<const std::uint32_t> cell_info
1180 = impl::get_cell_orientation_info(coeffs);
1183 for (std::size_t coeff = 0; coeff < coeffs.size(); ++coeff)
1185 impl::pack_coefficient_entity(
1186 std::span(c), cstride, *coeffs[coeff], cell_info, cells, 1,
1187 [](
auto entity) {
return entity[0]; }, offsets[coeff]);
1190 return {std::move(c), cstride};
1195template <
typename U>
1198 using T =
typename U::scalar_type;
1199 const std::vector<std::shared_ptr<const Constant<T>>>& constants
1203 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
1204 [](std::int32_t sum,
auto& constant)
1205 { return sum + constant->value.size(); });
1208 std::vector<T> constant_values(size);
1209 std::int32_t offset = 0;
1210 for (
auto& constant : constants)
1212 const std::vector<T>& value = constant->value;
1213 std::copy(value.begin(), value.end(),
1214 std::next(constant_values.begin(), offset));
1215 offset += value.size();
1218 return constant_values;
Degree-of-freedom map representations and tools.
Definition CoordinateElement.h:26
A timer can be used for timing tasks. The basic usage is.
Definition Timer.h:31
Constant value which can be attached to a Form.
Definition Constant.h:23
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:189
The class represents the degree-of-freedom (dofs) for an element. Dofs are associated with a mesh ent...
Definition ElementDofLayout.h:31
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell.
Definition Expression.h:41
const std::vector< std::shared_ptr< const Function< scalar_type, geometry_type > > > & coefficients() const
Get coefficients.
Definition Expression.h:112
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Expression.h:132
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:35
This class represents a function in a finite element function space , given by.
Definition Function.h:45
std::shared_ptr< const FunctionSpace< U > > function_space() const
Access the function space.
Definition Function.h:140
std::shared_ptr< const la::Vector< T > > x() const
Underlying vector.
Definition Function.h:146
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition AdjacencyList.h:28
std::span< T > links(std::size_t node)
Get the links (edges) for given node.
Definition AdjacencyList.h:112
Sparsity pattern data structure that can be used to initialize sparse matrices. After assembly,...
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
Finite element cell kernel concept.
Definition utils.h:122
Concepts for function that returns cell index.
Definition utils.h:832
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:803
std::array< std::int32_t, 2 *num_cells > get_cell_facet_pairs(std::int32_t f, const std::span< const std::int32_t > &cells, const graph::AdjacencyList< std::int32_t > &c_to_f)
Helper function to get an array of of (cell, local_facet) pairs corresponding to a given facet index.
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:853
Functions supporting mesh operations.
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
void cells(la::SparsityPattern &pattern, std::span< const std::int32_t > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:18
void interior_facets(la::SparsityPattern &pattern, std::span< const std::int32_t > facets, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over interior facets and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:28
Finite element method functionality.
Definition assemble_matrix_impl.h:25
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:146
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:920
std::vector< std::pair< int, std::vector< std::int32_t > > > compute_integration_domains(IntegralType integral_type, const mesh::Topology &topology, std::span< const std::int32_t > entities, int dim, std::span< const int > values)
Given an integral type and mesh tag data, compute the entities that should be integrated over.
Definition utils.cpp:156
Form< T, U > create_form(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::vector< std::int32_t > > > > &subdomains, std::shared_ptr< const mesh::Mesh< U > > mesh=nullptr)
Create a Form from UFC input.
Definition utils.h:279
std::vector< std::string > get_coefficient_names(const ufcx_form &ufcx_form)
Get the name of each coefficient in a UFC form.
Definition utils.cpp:137
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:135
std::vector< typename U::scalar_type > pack_constants(const U &u)
Pack constants of u of generic type U ready for assembly.
Definition utils.h:1196
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:1050
IntegralType
Type of integral.
Definition Form.h:33
@ 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:669
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:160
ElementDofLayout create_element_dof_layout(const ufcx_dofmap &dofmap, const mesh::CellType cell_type, const std::vector< int > &parent_map={})
Create an ElementDofLayout from a ufcx_dofmap.
Definition utils.cpp:32
DofMap create_dofmap(MPI_Comm comm, const ElementDofLayout &layout, mesh::Topology &topology, std::function< void(const std::span< std::int32_t > &, std::uint32_t)> unpermute_dofs, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn)
Create a dof map on mesh.
Definition utils.cpp:98
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:974