10 #include "CoordinateElement.h"
12 #include "ElementDofLayout.h"
13 #include "Expression.h"
16 #include <dolfinx/la/SparsityPattern.h>
17 #include <dolfinx/mesh/cell_types.h>
26 #include <xtensor/xadapt.hpp>
27 #include <xtensor/xtensor.hpp>
28 #include <xtl/xspan.hpp>
61 std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>>
64 std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>>
66 std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>(
68 for (std::size_t i = 0; i < a.size(); ++i)
70 for (std::size_t j = 0; j < a[i].size(); ++j)
72 if (
const Form<T>* form = a[i][j]; form)
73 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
84 const std::array<std::reference_wrapper<const DofMap>, 2>& dofmaps,
85 const std::set<IntegralType>& integrals);
97 throw std::runtime_error(
98 "Cannot create sparsity pattern. Form is not a bilinear form");
102 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
105 std::shared_ptr mesh = a.
mesh();
113 const int tdim = mesh->topology().dim();
114 mesh->topology_mutable().create_entities(tdim - 1);
115 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
124 const std::vector<int>& parent_map
137 mesh::Topology& topology,
138 const std::function<std::vector<int>(
139 const graph::AdjacencyList<std::int32_t>&)>& reorder_fn,
140 const FiniteElement& element);
159 template <
typename T>
161 const ufcx_form& ufcx_form,
162 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
163 const std::vector<std::shared_ptr<
const Function<T>>>& coefficients,
164 const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
166 const std::shared_ptr<const mesh::Mesh>& mesh =
nullptr)
168 if (ufcx_form.rank != (
int)spaces.size())
169 throw std::runtime_error(
"Wrong number of argument spaces for Form.");
170 if (ufcx_form.num_coefficients != (
int)coefficients.size())
172 throw std::runtime_error(
173 "Mismatch between number of expected and provided Form coefficients.");
175 if (ufcx_form.num_constants != (
int)constants.size())
177 throw std::runtime_error(
178 "Mismatch between number of expected and provided Form constants.");
183 for (std::size_t i = 0; i < spaces.size(); ++i)
185 assert(spaces[i]->element());
186 ufcx_finite_element* ufcx_element = ufcx_form.finite_elements[i];
187 assert(ufcx_element);
188 if (std::string(ufcx_element->signature)
189 != spaces[i]->element()->signature())
191 throw std::runtime_error(
192 "Cannot create form. Wrong type of function space for argument.");
199 using kern = std::function<void(T*,
const T*,
const T*,
const double*,
200 const int*,
const std::uint8_t*)>;
201 std::map<IntegralType, std::pair<std::vector<std::pair<int, kern>>,
205 bool needs_facet_permutations =
false;
208 std::vector<int> cell_integral_ids(ufcx_form.integral_ids(
cell),
209 ufcx_form.integral_ids(
cell)
210 + ufcx_form.num_integrals(
cell));
211 for (
int i = 0; i < ufcx_form.num_integrals(
cell); ++i)
213 ufcx_integral* integral = ufcx_form.integrals(
cell)[i];
217 if constexpr (std::is_same<T, float>::value)
218 k = integral->tabulate_tensor_float32;
219 else if constexpr (std::is_same<T, std::complex<float>>::value)
221 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
222 const int*,
const unsigned char*)
>(
223 integral->tabulate_tensor_complex64);
225 else if constexpr (std::is_same<T, double>::value)
226 k = integral->tabulate_tensor_float64;
227 else if constexpr (std::is_same<T, std::complex<double>>::value)
229 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
230 const int*,
const unsigned char*)
>(
231 integral->tabulate_tensor_complex128);
237 if (integral->needs_facet_permutations)
238 needs_facet_permutations =
true;
243 it != subdomains.end() and !cell_integral_ids.empty())
256 auto mesh = spaces[0]->mesh();
257 const int tdim = mesh->topology().dim();
258 spaces[0]->mesh()->topology_mutable().create_entities(tdim - 1);
263 std::vector<int> exterior_facet_integral_ids(
273 if constexpr (std::is_same<T, float>::value)
274 k = integral->tabulate_tensor_float32;
275 else if constexpr (std::is_same<T, std::complex<float>>::value)
277 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
278 const int*,
const unsigned char*)
>(
279 integral->tabulate_tensor_complex64);
281 else if constexpr (std::is_same<T, double>::value)
282 k = integral->tabulate_tensor_float64;
283 else if constexpr (std::is_same<T, std::complex<double>>::value)
285 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
286 const int*,
const unsigned char*)
>(
287 integral->tabulate_tensor_complex128);
292 exterior_facet_integral_ids[i], k);
293 if (integral->needs_facet_permutations)
294 needs_facet_permutations =
true;
299 it != subdomains.end() and !exterior_facet_integral_ids.empty())
305 std::vector<int> interior_facet_integral_ids(
315 if constexpr (std::is_same<T, float>::value)
316 k = integral->tabulate_tensor_float32;
317 else if constexpr (std::is_same<T, std::complex<float>>::value)
319 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
320 const int*,
const unsigned char*)
>(
321 integral->tabulate_tensor_complex64);
323 else if constexpr (std::is_same<T, double>::value)
324 k = integral->tabulate_tensor_float64;
325 else if constexpr (std::is_same<T, std::complex<double>>::value)
327 k =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
328 const int*,
const unsigned char*)
>(
329 integral->tabulate_tensor_complex128);
334 interior_facet_integral_ids[i], k);
335 if (integral->needs_facet_permutations)
336 needs_facet_permutations =
true;
341 it != subdomains.end() and !interior_facet_integral_ids.empty())
346 return Form<T>(spaces, integral_data, coefficients, constants,
347 needs_facet_permutations, mesh);
359 template <
typename T>
361 const ufcx_form& ufcx_form,
362 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
363 const std::map<std::string, std::shared_ptr<
const Function<T>>>&
365 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
367 const std::shared_ptr<const mesh::Mesh>& mesh =
nullptr)
370 std::vector<std::shared_ptr<const Function<T>>> coeff_map;
373 if (
auto it = coefficients.find(name); it != coefficients.end())
374 coeff_map.push_back(it->second);
377 throw std::runtime_error(
"Form coefficient \"" + name
378 +
"\" not provided.");
383 std::vector<std::shared_ptr<const Constant<T>>> const_map;
386 if (
auto it = constants.find(name); it != constants.end())
387 const_map.push_back(it->second);
389 throw std::runtime_error(
"Form constant \"" + name +
"\" not provided.");
392 return create_form(ufcx_form, spaces, coeff_map, const_map, subdomains, mesh);
406 template <
typename T>
408 ufcx_form* (*fptr)(),
409 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
410 const std::map<std::string, std::shared_ptr<
const Function<T>>>&
412 const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
414 const std::shared_ptr<const mesh::Mesh>& mesh =
nullptr)
416 ufcx_form* form = fptr();
417 Form<T> L = create_form<T>(*form, spaces, coefficients, constants, subdomains,
433 const basix::FiniteElement& e,
int bs,
434 const std::function<std::vector<int>(
451 ufcx_function_space* (*fptr)(
const char*),
const std::string& function_name,
452 const std::shared_ptr<mesh::Mesh>& mesh,
461 template <
typename T>
462 xtl::span<const std::uint32_t> get_cell_orientation_info(
463 const std::vector<std::shared_ptr<
const Function<T>>>& coefficients)
465 bool needs_dof_transformations =
false;
466 for (
auto coeff : coefficients)
468 std::shared_ptr<const FiniteElement> element
469 = coeff->function_space()->element();
470 if (element->needs_dof_transformations())
472 needs_dof_transformations =
true;
477 xtl::span<const std::uint32_t> cell_info;
478 if (needs_dof_transformations)
480 auto mesh = coefficients.front()->function_space()->mesh();
481 mesh->topology_mutable().create_entity_permutations();
482 cell_info = xtl::span(mesh->topology().get_cell_permutation_info());
489 template <
typename T,
int _bs,
typename Functor>
490 static inline void pack(
const xtl::span<T>& coeffs, std::int32_t cell,
int bs,
491 const xtl::span<const T>& v,
492 const xtl::span<const std::uint32_t>& cell_info,
493 const DofMap& dofmap, Functor transform)
495 auto dofs = dofmap.cell_dofs(cell);
496 for (std::size_t i = 0; i < dofs.size(); ++i)
498 if constexpr (_bs < 0)
500 const int pos_c = bs * i;
501 const int pos_v = bs * dofs[i];
502 for (
int k = 0; k < bs; ++k)
503 coeffs[pos_c + k] = v[pos_v + k];
507 const int pos_c = _bs * i;
508 const int pos_v = _bs * dofs[i];
509 for (
int k = 0; k < _bs; ++k)
510 coeffs[pos_c + k] = v[pos_v + k];
514 transform(coeffs, cell_info, cell, 1);
530 template <
typename T,
typename E,
typename Functor>
533 const xtl::span<const std::uint32_t>& cell_info,
534 const E& entities, Functor fetch_cells,
538 const xtl::span<const T>& v = u.
x()->array();
540 std::shared_ptr<const FiniteElement> element = u.
function_space()->element();
541 int space_dim = element->space_dimension();
542 const auto transformation
543 = element->get_dof_transformation_function<T>(
false,
true);
545 const int bs = dofmap.
bs();
549 for (std::size_t e = 0; e < entities.size(); ++e)
551 std::int32_t
cell = fetch_cells(entities[e]);
552 auto cell_coeff = c.subspan(e * cstride + offset, space_dim);
553 pack<T, 1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
557 for (std::size_t e = 0; e < entities.size(); ++e)
559 std::int32_t
cell = fetch_cells(entities[e]);
560 auto cell_coeff = c.subspan(e * cstride + offset, space_dim);
561 pack<T, 2>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
565 for (std::size_t e = 0; e < entities.size(); ++e)
567 std::int32_t
cell = fetch_cells(entities[e]);
568 auto cell_coeff = c.subspan(e * cstride + offset, space_dim);
569 pack<T, 3>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
573 for (std::size_t e = 0; e < entities.size(); ++e)
575 std::int32_t
cell = fetch_cells(entities[e]);
576 auto cell_coeff = c.subspan(e * cstride + offset, space_dim);
577 pack<T, -1>(cell_coeff,
cell, bs, v, cell_info, dofmap, transformation);
591 template <
typename T>
592 std::pair<std::vector<T>,
int>
597 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
601 std::size_t num_entities = 0;
603 if (!coefficients.empty())
605 cstride = offsets.back();
606 switch (integral_type)
618 throw std::runtime_error(
619 "Could not allocate coefficient data. Integral type not supported.");
623 return {std::vector<T>(num_entities * cstride), cstride};
630 template <
typename T>
631 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>>
634 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>,
int>> coeffs;
640 coeffs.end(), std::pair(integral_type,
id),
655 template <
typename T>
657 const xtl::span<T>& c,
int cstride)
660 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
664 if (!coefficients.empty())
666 xtl::span<const std::uint32_t> cell_info
667 = impl::get_cell_orientation_info(coefficients);
669 switch (integral_type)
673 auto fetch_cell = [](
auto entity) {
return entity; };
674 const std::vector<std::int32_t>& cells = form.
cell_domains(
id);
676 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
678 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
679 cell_info, cells, fetch_cell,
686 const std::vector<std::pair<std::int32_t, int>>& facets
690 auto fetch_cell = [](
auto& entity) {
return entity.first; };
693 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
695 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
696 cell_info, facets, fetch_cell,
704 const std::vector<std::tuple<std::int32_t, int, std::int32_t, int>>&
708 auto fetch_cell0 = [](
auto& entity) {
return std::get<0>(entity); };
709 auto fetch_cell1 = [](
auto& entity) {
return std::get<2>(entity); };
712 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
715 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
716 cell_info, facets, fetch_cell0,
719 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
720 cell_info, facets, fetch_cell1,
721 offsets[coeff] + offsets[coeff + 1]);
726 throw std::runtime_error(
727 "Could not pack coefficient. Integral type not supported.");
733 template <
typename T>
735 const ufcx_expression& expression,
738 const std::shared_ptr<const mesh::Mesh>& mesh =
nullptr,
739 const std::shared_ptr<const fem::FunctionSpace>& argument_function_space
742 if (expression.rank > 0 and !argument_function_space)
744 throw std::runtime_error(
745 "Expression has Argument but no Argument function space was provided.");
748 const int size = expression.num_points * expression.topological_dimension;
749 const xt::xtensor<double, 2> points = xt::adapt(
750 expression.points, size, xt::no_ownership(),
751 std::vector<std::size_t>(
752 {static_cast<std::size_t>(expression.num_points),
753 static_cast<std::size_t>(expression.topological_dimension)}));
755 std::vector<int> value_shape;
756 for (
int i = 0; i < expression.num_components; ++i)
757 value_shape.push_back(expression.value_shape[i]);
759 std::function<void(T*,
const T*,
const T*,
const double*,
const int*,
760 const std::uint8_t*)>
761 tabulate_tensor =
nullptr;
762 if constexpr (std::is_same<T, float>::value)
763 tabulate_tensor = expression.tabulate_tensor_float32;
764 else if constexpr (std::is_same<T, std::complex<float>>::value)
767 =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
768 const int*,
const unsigned char*)
>(
769 expression.tabulate_tensor_complex64);
771 else if constexpr (std::is_same<T, double>::value)
772 tabulate_tensor = expression.tabulate_tensor_float64;
773 else if constexpr (std::is_same<T, std::complex<double>>::value)
776 =
reinterpret_cast<void (*)(T*,
const T*,
const T*,
const double*,
777 const int*,
const unsigned char*)
>(
778 expression.tabulate_tensor_complex128);
782 throw std::runtime_error(
"Type not supported.");
784 assert(tabulate_tensor);
786 return fem::Expression(coefficients, constants, points, tabulate_tensor,
787 value_shape, mesh, argument_function_space);
792 template <
typename T>
794 const ufcx_expression& expression,
799 const std::shared_ptr<const mesh::Mesh>& mesh =
nullptr,
800 const std::shared_ptr<const fem::FunctionSpace>& argument_function_space
804 std::vector<std::shared_ptr<const fem::Function<T>>> coeff_map;
805 std::vector<std::string> coefficient_names;
806 for (
int i = 0; i < expression.num_coefficients; ++i)
807 coefficient_names.push_back(expression.coefficient_names[i]);
809 for (
const std::string& name : coefficient_names)
811 if (
auto it = coefficients.find(name); it != coefficients.end())
812 coeff_map.push_back(it->second);
815 throw std::runtime_error(
"Expression coefficient \"" + name
816 +
"\" not provided.");
821 std::vector<std::shared_ptr<const fem::Constant<T>>> const_map;
822 std::vector<std::string> constant_names;
823 for (
int i = 0; i < expression.num_constants; ++i)
824 constant_names.push_back(expression.constant_names[i]);
826 for (
const std::string& name : constant_names)
828 if (
auto it = constants.find(name); it != constants.end())
829 const_map.push_back(it->second);
832 throw std::runtime_error(
"Expression constant \"" + name
833 +
"\" not provided.");
838 argument_function_space);
846 template <
typename T>
848 std::map<std::pair<IntegralType, int>,
849 std::pair<std::vector<T>,
int>>& coeffs)
851 for (
auto& [key, val] : coeffs)
852 pack_coefficients<T>(form, key.first, key.second, val.first, val.second);
861 template <
typename T>
862 std::pair<std::vector<T>,
int>
864 const xtl::span<const std::int32_t>& cells)
867 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
872 const int cstride = offsets.back();
873 std::vector<T> c(cells.size() * offsets.back());
874 if (!coefficients.empty())
876 xtl::span<const std::uint32_t> cell_info
877 = impl::get_cell_orientation_info(coefficients);
880 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
881 impl::pack_coefficient_entity(
882 xtl::span(c), cstride, *coefficients[coeff], cell_info, cells,
883 [](std::int32_t entity) {
return entity; }, offsets[coeff]);
885 return {std::move(c), cstride};
890 template <
typename U>
893 using T =
typename U::scalar_type;
894 const std::vector<std::shared_ptr<const Constant<T>>>& constants
898 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
899 [](std::int32_t sum,
auto& constant)
900 { return sum + constant->value.size(); });
903 std::vector<T> constant_values(size);
904 std::int32_t offset = 0;
905 for (
auto& constant : constants)
907 const std::vector<T>& value = constant->value;
908 std::copy(value.cbegin(), value.cend(),
909 std::next(constant_values.begin(), offset));
910 offset += value.size();
913 return constant_values;
Degree-of-freedeom map representations ans tools.
Constant value which can be attached to a Form. Constants may be scalar (rank 0), vector (rank 1),...
Definition: Constant.h:21
Degree-of-freedom map.
Definition: DofMap.h:71
int bs() const noexcept
Return the block size for the dofmap.
Definition: DofMap.cpp:204
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell....
Definition: Expression.h:34
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell. Used to pack data for multiple coefficients in...
Definition: Expression.h:106
const std::vector< std::shared_ptr< const fem::Function< T > > > & coefficients() const
Get coefficients.
Definition: Expression.h:89
This class represents a function in a finite element function space , given by.
Definition: Function.h:45
std::shared_ptr< const la::Vector< T > > x() const
Underlying vector.
Definition: Function.h:142
std::shared_ptr< const FunctionSpace > function_space() const
Access the function space.
Definition: Function.h:136
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition: AdjacencyList.h:46
This class provides a sparsity pattern data structure that can be used to initialize sparse matrices....
Definition: SparsityPattern.h:34
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition: Topology.h:57
void pack_coefficient_entity(const xtl::span< T > &c, int cstride, const Function< T > &u, const xtl::span< const std::uint32_t > &cell_info, const E &entities, Functor fetch_cells, std::int32_t offset)
Pack a single coefficient for a set of active entities.
Definition: utils.h:531
Miscellaneous classes, functions and types.
Finite element method functionality.
Definition: assemble_matrix_impl.h:24
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:197
Form< T > create_form(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace >> &spaces, const std::vector< std::shared_ptr< const Function< T >>> &coefficients, const std::vector< std::shared_ptr< const Constant< T >>> &constants, const std::map< IntegralType, const mesh::MeshTags< int > * > &subdomains, const std::shared_ptr< const mesh::Mesh > &mesh=nullptr)
Create a Form from UFC input.
Definition: utils.h:160
fem::Expression< T > create_expression(const ufcx_expression &expression, const std::vector< std::shared_ptr< const fem::Function< T >>> &coefficients, const std::vector< std::shared_ptr< const fem::Constant< T >>> &constants, const std::shared_ptr< const mesh::Mesh > &mesh=nullptr, const std::shared_ptr< const fem::FunctionSpace > &argument_function_space=nullptr)
Create Expression from UFC.
Definition: utils.h:734
void pack_coefficients(const Form< T > &form, IntegralType integral_type, int id, const xtl::span< T > &c, int cstride)
Pack coefficients of a Form for a given integral type and domain id.
Definition: utils.h:656
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:891
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T > &form, IntegralType integral_type, int id)
Allocate storage for coefficients of a pair (integral_type, id) from a fem::Form form.
Definition: utils.h:593
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:188
std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace >, 2 > > > extract_function_spaces(const std::vector< std::vector< const Form< T > * >> &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition: utils.h:62
IntegralType
Type of integral.
Definition: Form.h:30
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
la::SparsityPattern create_sparsity_pattern(const mesh::Topology &topology, const std::array< std::reference_wrapper< const DofMap >, 2 > &dofmaps, const std::set< IntegralType > &integrals)
Create a sparsity pattern for a given form.
Definition: utils.cpp:31
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:74
FunctionSpace create_functionspace(const std::shared_ptr< mesh::Mesh > &mesh, const basix::FiniteElement &e, int bs, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn=nullptr)
Create a FunctionSpace from a Basix element.
Definition: utils.cpp:206
DofMap create_dofmap(MPI_Comm comm, const ElementDofLayout &layout, mesh::Topology &topology, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn, const FiniteElement &element)
Create a dof map on mesh.
Definition: utils.cpp:141
Mesh data structures and algorithms on meshes.
Definition: DofMap.h:30
CellType
Cell type identifier.
Definition: cell_types.h:22