10#include "FunctionSpace.h"
13#include <basix/mdspan.hpp>
17#include <dolfinx/common/types.h>
18#include <dolfinx/mesh/EntityMap.h>
19#include <dolfinx/mesh/Mesh.h>
20#include <dolfinx/mesh/cell_types.h>
36template <dolfinx::scalar T>
38template <dolfinx::scalar T, std::
floating_po
int U>
72 throw std::invalid_argument(
"Unknown integral type.");
90inline md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>>
97 const int tdim = topology.
dim();
103 return md::mdspan(p.data(), p.size() / num_entities_per_cell,
104 num_entities_per_cell);
111template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_t<T>>
119 template <
typename K,
typename V,
typename W>
120 requires std::is_convertible_v<
121 std::remove_cvref_t<K>,
122 std::function<void(T*,
const T*,
const T*,
const U*,
123 const int*,
const uint8_t*,
void*)>>
124 and std::is_convertible_v<std::remove_cvref_t<V>,
125 std::vector<std::int32_t>>
126 and std::is_convertible_v<std::remove_cvref_t<W>,
135 std::function<void(T*,
const T*,
const T*,
const U*,
const int*,
136 const uint8_t*,
void*)>
175template <dolfinx::scalar T, std::
floating_po
int U = dolfinx::scalar_value_t<T>>
210 template <
typename X>
211 requires std::is_convertible_v<
212 std::remove_cvref_t<X>,
213 std::map<std::tuple<IntegralType, int, int>,
224 const std::vector<std::reference_wrapper<const mesh::EntityMap>>&
226 : _function_spaces(V), _integrals(std::forward<X>(integrals)),
231 throw std::invalid_argument(
"Form Mesh is null.");
237 const int tdim = topology.
dim();
243 auto it = std::ranges::find_if(
247 return ((em.
topology() == mesh0->topology()
253 if (it == entity_maps.end())
255 throw std::invalid_argument(
256 "Incompatible mesh. argument entity_maps must be provided.");
264 auto compute_entity_domains
265 = [](
const auto& int_ents_mesh,
int codim,
const auto& c_to_e,
266 const auto& emap,
bool inverse)
273 std::vector<std::int32_t> entities;
274 entities.reserve(int_ents_mesh.size() / 2);
280 for (std::size_t i = 0; i < int_ents_mesh.size(); i += 2)
281 entities.push_back(int_ents_mesh[i]);
289 for (std::size_t i = 0; i < int_ents_mesh.size(); i += 2)
292 c_to_e->links(int_ents_mesh[i])[int_ents_mesh[i + 1]]);
298 std::vector<std::int32_t> cells_mesh0
299 = emap.sub_topology_to_topology(entities,
inverse);
306 std::vector<std::int32_t> e = int_ents_mesh;
307 for (std::size_t i = 0; i < cells_mesh0.size(); ++i)
308 e[2 * i] = cells_mesh0[i];
318 auto map_entities = [tdim, &topology, &compute_entity_domains](
322 bool inverse) -> std::vector<std::int32_t>
325 return emap.sub_topology_to_topology(entities,
inverse);
329 throw std::invalid_argument(
330 "Vertex integrals are not supported for a form with an argument "
331 "or coefficient on another mesh. Supported types are cell, "
332 "exterior facet, interior facet and ridge.");
335 const int dim0 = mesh0.topology()->dim();
336 const int codim = tdim - dim0;
339 if (codim > 0 and edim != dim0)
341 throw std::invalid_argument(std::format(
342 "Cannot map integration entities of dimension {} to cells of a "
343 "mesh of dimension {}. An argument or coefficient on another mesh "
344 "must live on the entities being integrated over.",
348 std::shared_ptr<const graph::AdjacencyList<std::int32_t>> c_to_e
350 assert(codim == 0 or c_to_e);
351 return compute_entity_domains(entities, codim, c_to_e, emap,
inverse);
354 _edata.reserve(_function_spaces.size());
355 for (
auto& space : _function_spaces)
358 std::map<std::tuple<IntegralType, int, int>,
359 std::variant<std::vector<std::int32_t>,
360 std::span<const std::int32_t>>>
363 if (
auto mesh0 = space->mesh(); mesh0 == _mesh)
365 for (
auto& [key, integral] : _integrals)
366 vdata.insert({key, std::span(integral.entities)});
377 for (
auto& [key, itg] : _integrals)
379 auto [type, idx, kernel_idx] = key;
380 std::vector<std::int32_t> e;
382 e = map_entities(type, itg.entities, *mesh0, emap,
inverse);
384 vdata.insert({key, std::move(e)});
388 _edata.push_back(std::move(vdata));
391 for (
auto& [key, integral] : _integrals)
393 auto [type, idx, kernel_idx] = key;
394 for (
int c : integral.coeffs)
396 if (
auto mesh0 =
coefficients.at(c)->function_space()->mesh();
399 _cdata.insert({{type, idx, c}, std::span(integral.entities)});
407 std::vector<std::int32_t> e;
409 e = map_entities(type, integral.entities, *mesh0, emap,
inverse);
410 _cdata.insert({{type, idx, c}, std::move(e)});
431 Form(
Form&& form)
noexcept =
default;
441 Form& operator=(
const Form& form) =
delete;
455 int rank()
const {
return _function_spaces.size(); }
459 std::shared_ptr<const mesh::Mesh<geometry_type>>
mesh()
const
466 const std::vector<std::shared_ptr<const FunctionSpace<geometry_type>>>&
469 return _function_spaces;
484 auto it = _integrals.find({type, idx, kernel_idx});
485 if (it == _integrals.end())
486 throw std::out_of_range(
"Requested integral kernel not found.");
487 return it->second.kernel;
494 std::set<IntegralType> types;
495 for (
auto& [key, integral] : _integrals)
496 types.insert(std::get<0>(key));
515 auto it = std::ranges::find_if(_integrals,
518 auto [t, idx_, kernel_idx] = x.first;
519 return t == type and idx_ == idx;
521 if (it == _integrals.end())
522 throw std::out_of_range(
"Could not find active coefficient list.");
523 return it->second.coeffs;
544 return std::ranges::count_if(_integrals,
545 [type, kernel_idx](
auto& x)
547 auto [t, id, k_idx] = x.first;
548 return t == type and k_idx == kernel_idx;
587 int kernel_idx)
const
589 auto it = _integrals.find({type, idx, kernel_idx});
590 if (it == _integrals.end())
591 throw std::out_of_range(
"Requested domain not found.");
592 return it->second.entities;
631 int kernel_idx)
const
633 auto it = _edata.at(
rank).find({type, idx, kernel_idx});
634 if (it == _edata.at(
rank).end())
635 throw std::out_of_range(
"Requested domain for argument not found.");
637 return std::visit([](
const auto& v) -> std::span<const std::int32_t>
638 {
return v; }, it->second);
658 auto it = _cdata.find({type, idx, c});
659 if (it == _cdata.end())
660 throw std::out_of_range(
"No domain for requested integral.");
661 return std::visit([](
const auto& v) -> std::span<const std::int32_t>
662 {
return v; }, it->second);
668 std::shared_ptr<const Function<scalar_type, geometry_type>>>&
671 return _coefficients;
687 std::vector<int> n{0};
688 n.reserve(_coefficients.size() + 1);
689 for (
auto& c : _coefficients)
692 throw std::runtime_error(
"Not all form coefficients have been set.");
693 n.push_back(n.back() + c->function_space()->element()->space_dimension());
700 const std::vector<std::shared_ptr<const Constant<scalar_type>>>&
708 std::vector<std::shared_ptr<const FunctionSpace<geometry_type>>>
712 std::map<std::tuple<IntegralType, int, int>,
717 std::shared_ptr<const mesh::Mesh<geometry_type>> _mesh;
720 std::vector<std::shared_ptr<const Function<scalar_type, geometry_type>>>
724 std::vector<std::shared_ptr<const Constant<scalar_type>>> _constants;
727 bool _needs_facet_permutations;
739 std::vector<std::map<
740 std::tuple<IntegralType, int, int>,
741 std::variant<std::vector<std::int32_t>, std::span<const std::int32_t>>>>
757 std::tuple<IntegralType, int, int>,
758 std::variant<std::vector<std::int32_t>, std::span<const std::int32_t>>>
Constant (in space) value which can be attached to a Form.
Definition Constant.h:22
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:35
A bidirectional map relating entities in one topology to another.
Definition EntityMap.h:27
std::shared_ptr< const Topology > sub_topology() const
Get the sub-topology.
Definition EntityMap.cpp:20
std::shared_ptr< const Topology > topology() const
Get the (parent) topology.
Definition EntityMap.cpp:15
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:49
void create_entity_permutations(int dim, int num_threads=1)
Compute entity permutations and reflections.
Definition Topology.cpp:1098
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(std::array< int, 2 > d0, std::array< int, 2 > d1) const
Get the connectivity from entities of topological dimension d0 to dimension d1.
Definition Topology.cpp:939
int dim() const noexcept
Topological dimension of the mesh.
Definition Topology.cpp:878
const std::vector< std::uint8_t > & get_entity_permutations(int dim) const
Get the numbers that encode the permutation to apply to each cell-local entity of a given dimension.
Definition Topology.cpp:973
Finite element method functionality.
Definition assemble_expression_impl.h:22
@ inverse
Inverse.
Definition FiniteElement.h:33
IntegralType
Type of integral.
Definition Form.h:43
@ vertex
Vertex.
Definition Form.h:47
@ interior_facet
Interior facet.
Definition Form.h:46
@ ridge
Ridge.
Definition Form.h:48
@ cell
Cell.
Definition Form.h:44
@ exterior_facet
Exterior facet.
Definition Form.h:45
constexpr int integral_entity_dim(IntegralType type, int tdim)
Topological dimension of the mesh entities an integral of the given type is over.
Definition Form.h:57
CellType
Cell type identifier.
Definition cell_types.h:24
int cell_num_entities(CellType type, int dim)
Number of entities of dimension.
Definition cell_types.cpp:97
Represents integral data, containing the kernel, and a list of entities to integrate over and the ind...
Definition Form.h:113
std::function< void(T *, const T *, const T *, const U *, const int *, const uint8_t *, void *)> kernel
The integration kernel.
Definition Form.h:137
integral_data(K &&kernel, V &&entities, W &&coeffs)
Create a structure to hold integral data.
Definition Form.h:128
std::vector< int > coeffs
Indices of coefficients (from the form) that are in this integral.
Definition Form.h:145
std::vector< std::int32_t > entities
The entities to integrate over for this integral. These are the entities in 'full' mesh.
Definition Form.h:141