Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/d8/d18/Form_8h_source.html
DOLFINx 0.8.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
Form.h
1// Copyright (C) 2019-2023 Garth N. Wells and Chris Richardson
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include "FunctionSpace.h"
10#include "traits.h"
11#include <algorithm>
12#include <array>
13#include <concepts>
14#include <dolfinx/common/IndexMap.h>
15#include <dolfinx/common/types.h>
16#include <dolfinx/mesh/Mesh.h>
17#include <functional>
18#include <memory>
19#include <span>
20#include <string>
21#include <tuple>
22#include <vector>
23
24namespace dolfinx::fem
25{
26
27template <dolfinx::scalar T>
28class Constant;
29template <dolfinx::scalar T, std::floating_point U>
30class Function;
31
33enum class IntegralType : std::int8_t
34{
35 cell = 0,
36 exterior_facet = 1,
37 interior_facet = 2,
38 vertex = 3
39};
40
43template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
45{
51 template <typename K, typename V>
52 requires std::is_convertible_v<
53 std::remove_cvref_t<K>,
54 std::function<void(T*, const T*, const T*, const U*,
55 const int*, const uint8_t*)>>
56 and std::is_convertible_v<std::remove_cvref_t<V>,
57 std::vector<std::int32_t>>
58 integral_data(int id, K&& kernel, V&& entities)
59 : id(id), kernel(std::forward<K>(kernel)),
60 entities(std::forward<V>(entities))
61 {
62 }
63
68 template <typename K>
69 requires std::is_convertible_v<
70 std::remove_cvref_t<K>,
71 std::function<void(T*, const T*, const T*, const U*,
72 const int*, const uint8_t*)>>
73 integral_data(int id, K&& kernel, std::span<const std::int32_t> e)
74 : id(id), kernel(std::forward<K>(kernel)), entities(e.begin(), e.end())
75 {
76 }
77
79 int id;
80
82 std::function<void(T*, const T*, const T*, const U*, const int*,
83 const uint8_t*)>
85
87 std::vector<std::int32_t> entities;
88};
89
117template <dolfinx::scalar T,
118 std::floating_point U = dolfinx::scalar_value_type_t<T>>
119class Form
120{
121public:
123 using scalar_type = T;
124
153 template <typename X>
154 requires std::is_convertible_v<
155 std::remove_cvref_t<X>,
156 std::map<IntegralType, std::vector<integral_data<T, U>>>>
157 Form(const std::vector<std::shared_ptr<const FunctionSpace<U>>>& V,
158 X&& integrals,
159 const std::vector<std::shared_ptr<const Function<scalar_type, U>>>&
161 const std::vector<std::shared_ptr<const Constant<scalar_type>>>&
162 constants,
164 const std::map<std::shared_ptr<const mesh::Mesh<U>>,
165 std::span<const std::int32_t>>& entity_maps,
166 std::shared_ptr<const mesh::Mesh<U>> mesh = nullptr)
167 : _function_spaces(V), _coefficients(coefficients), _constants(constants),
168 _mesh(mesh), _needs_facet_permutations(needs_facet_permutations)
169 {
170 // Extract _mesh from FunctionSpace, and check they are the same
171 if (!_mesh and !V.empty())
172 _mesh = V[0]->mesh();
173 for (auto& space : V)
174 {
175 if (_mesh != space->mesh()
176 and entity_maps.find(space->mesh()) == entity_maps.end())
177 {
178 throw std::runtime_error(
179 "Incompatible mesh. entity_maps must be provided.");
180 }
181 }
182 if (!_mesh)
183 throw std::runtime_error("No mesh could be associated with the Form.");
184
185 // Store kernels, looping over integrals by domain type (dimension)
186 for (auto&& [domain_type, data] : integrals)
187 {
188 if (!std::is_sorted(data.begin(), data.end(),
189 [](auto& a, auto& b) { return a.id < b.id; }))
190 {
191 throw std::runtime_error("Integral IDs not sorted");
192 }
193
194 std::vector<integral_data<T, U>>& itg
195 = _integrals[static_cast<std::size_t>(domain_type)];
196 for (auto&& [id, kern, e] : data)
197 itg.emplace_back(id, kern, std::move(e));
198 }
199
200 // Store entity maps
201 for (auto [msh, map] : entity_maps)
202 _entity_maps.insert({msh, std::vector(map.begin(), map.end())});
203 }
204
206 Form(const Form& form) = delete;
207
209 Form(Form&& form) = default;
210
212 virtual ~Form() = default;
213
219 int rank() const { return _function_spaces.size(); }
220
223 std::shared_ptr<const mesh::Mesh<U>> mesh() const { return _mesh; }
224
227 const std::vector<std::shared_ptr<const FunctionSpace<U>>>&
229 {
230 return _function_spaces;
231 }
232
238 std::function<void(T*, const T*, const T*, const U*, const int*,
239 const uint8_t*)>
240 kernel(IntegralType type, int i) const
241 {
242 const auto& integrals = _integrals[static_cast<std::size_t>(type)];
243 auto it = std::lower_bound(integrals.begin(), integrals.end(), i,
244 [](auto& itg_data, int i)
245 { return itg_data.id < i; });
246 if (it != integrals.end() and it->id == i)
247 return it->kernel;
248 else
249 throw std::runtime_error("No kernel for requested domain index.");
250 }
251
254 std::set<IntegralType> integral_types() const
255 {
256 std::set<IntegralType> set;
257 for (std::size_t i = 0; i < _integrals.size(); ++i)
258 {
259 if (!_integrals[i].empty())
260 set.insert(static_cast<IntegralType>(i));
261 }
262
263 return set;
264 }
265
270 {
271 return _integrals[static_cast<std::size_t>(type)].size();
272 }
273
281 std::vector<int> integral_ids(IntegralType type) const
282 {
283 std::vector<int> ids;
284 const auto& integrals = _integrals[static_cast<std::size_t>(type)];
285 std::transform(integrals.begin(), integrals.end(), std::back_inserter(ids),
286 [](auto& integral) { return integral.id; });
287 return ids;
288 }
289
307 std::span<const std::int32_t> domain(IntegralType type, int i) const
308 {
309 const auto& integrals = _integrals[static_cast<std::size_t>(type)];
310 auto it = std::lower_bound(integrals.begin(), integrals.end(), i,
311 [](auto& itg_data, int i)
312 { return itg_data.id < i; });
313 if (it != integrals.end() and it->id == i)
314 return it->entities;
315 else
316 throw std::runtime_error("No mesh entities for requested domain index.");
317 }
318
327 std::vector<std::int32_t> domain(IntegralType type, int i,
328 const mesh::Mesh<U>& mesh) const
329 {
330 // Hack to avoid passing shared pointer to this function
331 std::shared_ptr<const mesh::Mesh<U>> msh_ptr(&mesh,
332 [](const mesh::Mesh<U>*) {});
333
334 std::span<const std::int32_t> entities = domain(type, i);
335 if (msh_ptr == _mesh)
336 return std::vector(entities.begin(), entities.end());
337 else
338 {
339 std::span<const std::int32_t> entity_map = _entity_maps.at(msh_ptr);
340 std::vector<std::int32_t> mapped_entities;
341 mapped_entities.reserve(entities.size());
342 switch (type)
343 {
345 {
346 std::transform(entities.begin(), entities.end(),
347 std::back_inserter(mapped_entities),
348 [&entity_map](auto e) { return entity_map[e]; });
349 break;
350 }
352 // Exterior and interior facets are treated the same
353 [[fallthrough]];
355 {
356 for (std::size_t i = 0; i < entities.size(); i += 2)
357 {
358 // Add cell and the local facet index
359 mapped_entities.insert(mapped_entities.end(),
360 {entity_map[entities[i]], entities[i + 1]});
361 }
362 break;
363 }
364 default:
365 throw std::runtime_error("Integral type not supported.");
366 }
367
368 return mapped_entities;
369 }
370 }
371
373 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients() const
374 {
375 return _coefficients;
376 }
377
381 bool needs_facet_permutations() const { return _needs_facet_permutations; }
382
387 std::vector<int> coefficient_offsets() const
388 {
389 std::vector<int> n = {0};
390 for (auto& c : _coefficients)
391 {
392 if (!c)
393 throw std::runtime_error("Not all form coefficients have been set.");
394 n.push_back(n.back() + c->function_space()->element()->space_dimension());
395 }
396 return n;
397 }
398
400 const std::vector<std::shared_ptr<const Constant<T>>>& constants() const
401 {
402 return _constants;
403 }
404
405private:
406 // Function spaces (one for each argument)
407 std::vector<std::shared_ptr<const FunctionSpace<U>>> _function_spaces;
408
409 // Integrals. Array index is
410 // static_cast<std::size_t(IntegralType::foo)
411 std::array<std::vector<integral_data<T, U>>, 4> _integrals;
412
413 // Form coefficients
414 std::vector<std::shared_ptr<const Function<T, U>>> _coefficients;
415
416 // Constants associated with the Form
417 std::vector<std::shared_ptr<const Constant<T>>> _constants;
418
419 // The mesh
420 std::shared_ptr<const mesh::Mesh<U>> _mesh;
421
422 // True if permutation data needs to be passed into these integrals
423 bool _needs_facet_permutations;
424
425 // Entity maps (see Form documentation)
426 std::map<std::shared_ptr<const mesh::Mesh<U>>, std::vector<std::int32_t>>
427 _entity_maps;
428}; // namespace dolfinx::fem
429} // namespace dolfinx::fem
Constant value which can be attached to a Form.
Definition Constant.h:23
A representation of finite element variational forms.
Definition Form.h:120
const std::vector< std::shared_ptr< const FunctionSpace< U > > > & function_spaces() const
Function spaces for all arguments.
Definition Form.h:228
bool needs_facet_permutations() const
Get bool indicating whether permutation data needs to be passed into these integrals.
Definition Form.h:381
Form(Form &&form)=default
Move constructor.
int rank() const
Rank of the form.
Definition Form.h:219
std::shared_ptr< const mesh::Mesh< U > > mesh() const
Extract common mesh for the form.
Definition Form.h:223
Form(const Form &form)=delete
Copy constructor.
std::vector< std::int32_t > domain(IntegralType type, int i, const mesh::Mesh< U > &mesh) const
Compute the list of entity indices in mesh for the ith integral (kernel) of a given type (i....
Definition Form.h:327
virtual ~Form()=default
Destructor.
std::function< void(T *, const T *, const T *, const U *, const int *, const uint8_t *) kernel)(IntegralType type, int i) const
Get the kernel function for integral i on given domain type.
Definition Form.h:240
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Form.h:387
std::span< const std::int32_t > domain(IntegralType type, int i) const
Get the list of mesh entity indices for the ith integral (kernel) of a given type.
Definition Form.h:307
Form(const std::vector< std::shared_ptr< const FunctionSpace< U > > > &V, X &&integrals, const std::vector< std::shared_ptr< const Function< scalar_type, U > > > &coefficients, const std::vector< std::shared_ptr< const Constant< scalar_type > > > &constants, bool needs_facet_permutations, 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 finite element form.
Definition Form.h:157
const std::vector< std::shared_ptr< const Constant< T > > > & constants() const
Access constants.
Definition Form.h:400
std::vector< int > integral_ids(IntegralType type) const
Get the IDs for integrals (kernels) for given integral type.
Definition Form.h:281
std::set< IntegralType > integral_types() const
Get types of integrals in the form.
Definition Form.h:254
int num_integrals(IntegralType type) const
Number of integrals on given domain type.
Definition Form.h:269
T scalar_type
Scalar type.
Definition Form.h:123
const std::vector< std::shared_ptr< const Function< T, U > > > & coefficients() const
Access coefficients.
Definition Form.h:373
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:34
Definition Function.h:45
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Definition types.h:20
Finite element method functionality.
Definition assemble_matrix_impl.h:26
IntegralType
Type of integral.
Definition Form.h:34
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
Represents integral data, containing the integral ID, the kernel, and a list of entities to integrate...
Definition Form.h:45
integral_data(int id, K &&kernel, std::span< const std::int32_t > e)
Create a structure to hold integral data.
Definition Form.h:73
std::function< void(T *, const T *, const T *, const U *, const int *, const uint8_t *) kernel)
The integration kernel.
Definition Form.h:84
int id
Integral ID.
Definition Form.h:79
integral_data(int id, K &&kernel, V &&entities)
Create a structure to hold integral data.
Definition Form.h:58
std::vector< std::int32_t > entities
The entities to integrate over.
Definition Form.h:87