DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
assembler.h
Go to the documentation of this file.
1// Copyright (C) 2018-2026 Garth N. Wells and Jørgen S. Dokken
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 "assemble_matrix_impl.h"
11#include "assemble_scalar_impl.h"
12#include "assemble_vector_impl.h"
13#include "pack.h"
14#include "traits.h"
15#include <algorithm>
16#include <array>
17#include <basix/mdspan.hpp>
18#include <cstddef>
19#include <cstdint>
20#include <dolfinx/common/IndexMap.h>
21#include <dolfinx/common/log.h>
22#include <dolfinx/common/sort.h>
23#include <dolfinx/common/types.h>
24#include <dolfinx/la/utils.h>
25#include <dolfinx/mesh/EntityMap.h>
26#include <format>
27#include <functional>
28#include <map>
29#include <memory>
30#include <optional>
31#include <ranges>
32#include <span>
33#include <stdexcept>
34#include <utility>
35#include <vector>
36
39
40namespace dolfinx::fem
41{
42template <dolfinx::scalar T, std::floating_point U>
43class DirichletBC;
44template <dolfinx::scalar T, std::floating_point U>
45class Form;
46template <std::floating_point T>
47class FunctionSpace;
48
49// -- Helper functions -----------------------------------------------------
50
52template <dolfinx::scalar T>
53std::map<std::pair<IntegralType, int>, std::pair<std::span<const T>, int>>
54make_coefficients_span(const std::map<std::pair<IntegralType, int>,
55 std::pair<std::vector<T>, int>>& coeffs)
56{
57 using Key = typename std::remove_reference_t<decltype(coeffs)>::key_type;
58 std::map<Key, std::pair<std::span<const T>, int>> c;
59 std::ranges::transform(
60 coeffs, std::inserter(c, c.end()),
61 [](auto& e) -> typename decltype(c)::value_type
62 { return {e.first, {e.second.first, e.second.second}}; });
63 return c;
64}
65
66// -- Scalar ----------------------------------------------------------------
67
79template <dolfinx::scalar T, std::floating_point U>
81 const Form<T, U>& M, std::span<const T> constants,
82 const std::map<std::pair<IntegralType, int>,
83 std::pair<std::span<const T>, int>>& coefficients)
84{
85 using mdspanx3_t
86 = md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>>;
87
88 std::shared_ptr<const mesh::Mesh<U>> mesh = M.mesh();
89 assert(mesh);
90 std::span x = mesh->geometry().x();
91
92 // Accumulate contributions from each cell type
93 const int num_cell_types = mesh->topology()->cell_types().size();
94 T val = 0;
95 for (int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
96 {
97 // Geometry dofmap and data
98 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> x_dofmap
99 = mesh->geometry().dofmaps().at(cell_type_idx);
100 val += impl::assemble_scalar(M, x_dofmap,
101 mdspanx3_t(x.data(), x.size() / 3, 3),
102 constants, coefficients, cell_type_idx);
103 }
104 return val;
105}
106
114template <dolfinx::scalar T, std::floating_point U>
116{
117 const std::vector<T> constants = pack_constants(M);
118 auto coefficients = allocate_coefficient_storage(M);
119 pack_coefficients(M, coefficients);
120 return assemble_scalar(M, std::span(constants),
121 make_coefficients_span(coefficients));
122}
123
124// -- Vectors ----------------------------------------------------------------
125
136// template <dolfinx::scalar T, std::floating_point U>
137template <typename V, std::floating_point U,
138 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
139 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
141 V&& b, const Form<T, U>& L, std::span<const T> constants,
142 const std::map<std::pair<IntegralType, int>,
143 std::pair<std::span<const T>, int>>& coefficients)
144{
145 impl::assemble_vector(b, L, constants, coefficients);
146}
147
152// template <dolfinx::scalar T, std::floating_point U>
153// void assemble_vector(std::span<T> b, const Form<T, U>& L)
154template <typename V, std::floating_point U,
155 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
156 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
157void assemble_vector(V&& b, const Form<T, U>& L)
158{
159 auto coefficients = allocate_coefficient_storage(L);
160 pack_coefficients(L, coefficients);
161 const std::vector<T> constants = pack_constants(L);
162 assemble_vector(b, L, std::span(constants),
163 make_coefficients_span(coefficients));
164}
165
166namespace impl
167{
173template <dolfinx::scalar T, std::floating_point U>
174std::vector<std::int8_t> bc_dof_markers(
175 const FunctionSpace<U>& V,
176 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
177{
178 std::vector<std::int8_t> markers;
179 for (auto& bc : bcs)
180 {
181 assert(bc.get().function_space());
182 if (V.contains(*bc.get().function_space()))
183 {
184 if (markers.empty())
185 {
186 std::shared_ptr<const DofMap> dofmap = V.dofmaps().front();
187 std::shared_ptr<const common::IndexMap> map = dofmap->index_map;
188 assert(map);
189 markers.resize(dofmap->index_map_bs()
190 * (map->size_local() + map->num_ghosts()),
191 0);
192 }
193 bc.get().mark_dofs(markers);
194 }
195 }
196 return markers;
197}
198
214template <dolfinx::scalar T, std::floating_point U>
215std::array<std::span<const std::int8_t>, 2> bc_dof_markers_pair(
216 const Form<T, U>& a,
217 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs,
218 std::array<std::vector<std::int8_t>, 2>& storage)
219{
220 storage[0] = bc_dof_markers(*a.function_spaces().at(0), bcs);
221 std::span<const std::int8_t> marker0(storage[0]);
222 if (a.function_spaces().at(0) == a.function_spaces().at(1))
223 return {marker0, marker0};
224
225 storage[1] = bc_dof_markers(*a.function_spaces().at(1), bcs);
226 return {marker0, std::span<const std::int8_t>(storage[1])};
227}
228
233template <dolfinx::scalar T, std::floating_point U>
234std::pair<std::vector<std::vector<std::int8_t>>, std::vector<std::vector<T>>>
236 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
237 a,
238 const std::vector<
239 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1)
240{
241 if (a.size() != bcs1.size())
242 {
243 throw std::invalid_argument(
244 "Mismatch in size between a and bcs in assembler.");
245 }
246
247 std::vector<std::vector<std::int8_t>> markers(a.size());
248 std::vector<std::vector<T>> values(a.size());
249 for (std::size_t j = 0; j < a.size(); ++j)
250 {
251 if (a[j] and !bcs1[j].empty())
252 {
253 std::shared_ptr<const DofMap> dofmap
254 = a[j]->get().function_spaces().at(1)->dofmaps().front();
255 std::shared_ptr<const common::IndexMap> map1 = dofmap->index_map;
256 assert(map1);
257 const std::int32_t crange
258 = dofmap->index_map_bs() * (map1->size_local() + map1->num_ghosts());
259 markers[j].assign(crange, 0);
260 values[j].assign(crange, 0);
261 for (auto& bc : bcs1[j])
262 {
263 bc.get().mark_dofs(markers[j]);
264 bc.get().set(values[j], std::nullopt, 1);
265 }
266 }
267 }
268
269 return {std::move(markers), std::move(values)};
270}
271} // namespace impl
272
306template <typename V,
307 std::floating_point U
308 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
309 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
310 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
312 V&& b,
313 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
314 a,
315 const std::vector<std::span<const T>>& constants,
316 const std::vector<std::map<std::pair<IntegralType, int>,
317 std::pair<std::span<const T>, int>>>& coeffs,
318 const std::vector<std::span<const std::int8_t>>& bc_markers1,
319 const std::vector<std::span<const T>>& bc_values1,
320 const std::vector<std::span<const T>>& x0, T alpha)
321{
322 // If all forms are null, there is nothing to do
323 if (std::ranges::all_of(a, [](auto ai) { return !ai; }))
324 return;
325
326 common::Timer t("[Apply lifting]");
327
328 if (!x0.empty() and x0.size() != a.size())
329 {
330 throw std::invalid_argument(
331 "Mismatch in size between x0 and bilinear form in assembler.");
332 }
333
334 if (bc_markers1.size() != a.size() or bc_values1.size() != a.size())
335 {
336 throw std::invalid_argument(
337 "Mismatch in size between a and bc markers/values in assembler.");
338 }
339
340 for (std::size_t j = 0; j < a.size(); ++j)
341 {
342 if (!a[j] or bc_markers1[j].empty())
343 continue;
344
345 assert(a[j]->get().function_spaces().at(0));
346 auto V1 = a[j]->get().function_spaces()[1];
347 assert(V1);
348
349 std::shared_ptr<const DofMap> dofmap = V1->dofmaps().front();
350 auto map1 = dofmap->index_map;
351 assert(map1);
352 const std::size_t crange
353 = dofmap->index_map_bs() * (map1->size_local() + map1->num_ghosts());
354 if (bc_markers1[j].size() != crange or bc_values1[j].size() != crange)
355 {
356 throw std::invalid_argument(std::format(
357 "bc markers/values for block {} have length {}/{}, expected {}.", j,
358 bc_markers1[j].size(), bc_values1[j].size(), crange));
359 }
360
361 const int bs0 = a[j]->get().function_spaces()[0]->dofmaps().front()->bs();
362 const int bs1 = dofmap->bs();
363
364 std::span<const T> _x0;
365 if (!x0.empty())
366 _x0 = x0[j];
367
368 impl::dispatch_bs(bs0, bs1,
369 [&b, &a, j, &constants, &coeffs, &bc_values1,
370 &bc_markers1, &_x0, alpha](auto bs0, auto bs1)
371 {
372 impl::lift_bc(b, a[j]->get(), bs0, bs1, constants[j],
373 coeffs[j], bc_values1[j], bc_markers1[j],
374 _x0, alpha);
375 });
376 }
377}
378
461template <typename V,
462 std::floating_point U
463 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
464 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
465 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
467 V&& b,
468 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
469 a,
470 const std::vector<std::span<const T>>& constants,
471 const std::vector<std::map<std::pair<IntegralType, int>,
472 std::pair<std::span<const T>, int>>>& coeffs,
473 const std::vector<
474 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
475 const std::vector<std::span<const T>>& x0, T alpha)
476{
477 auto [bc_markers1, bc_values1] = impl::bc_lifting_data(a, bcs1);
479 b, a, constants, coeffs,
480 std::vector<std::span<const std::int8_t>>(bc_markers1.begin(),
481 bc_markers1.end()),
482 std::vector<std::span<const T>>(bc_values1.begin(), bc_values1.end()), x0,
483 alpha);
484}
485
519template <typename V,
520 std::floating_point U
521 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
522 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
523 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
525 V&& b,
526 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
527 a,
528 const std::vector<
529 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
530 const std::vector<std::span<const T>>& x0, T alpha)
531{
532 std::vector<
533 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>>>
534 coeffs;
535 std::vector<std::vector<T>> constants;
536 for (const auto& _a : a)
537 {
538 if (_a)
539 {
540 auto coefficients = allocate_coefficient_storage(_a->get());
541 pack_coefficients(_a->get(), coefficients);
542 coeffs.push_back(coefficients);
543 constants.push_back(pack_constants(_a->get()));
544 }
545 else
546 {
547 coeffs.emplace_back();
548 constants.emplace_back();
549 }
550 }
551
552 std::vector<std::span<const T>> _constants(constants.begin(),
553 constants.end());
554 std::vector<std::map<std::pair<IntegralType, int>,
555 std::pair<std::span<const T>, int>>>
556 _coeffs;
557 std::ranges::transform(coeffs, std::back_inserter(_coeffs),
558 [](auto& c) { return make_coefficients_span(c); });
559
560 auto [bc_markers1, bc_values1] = impl::bc_lifting_data(a, bcs1);
562 b, a, _constants, _coeffs,
563 std::vector<std::span<const std::int8_t>>(bc_markers1.begin(),
564 bc_markers1.end()),
565 std::vector<std::span<const T>>(bc_values1.begin(), bc_values1.end()), x0,
566 alpha);
567}
568
569// -- Matrices ---------------------------------------------------------------
570
587template <dolfinx::scalar T, std::floating_point U>
589 la::MatSet<T> auto mat_add, const Form<T, U>& a,
590 std::span<const T> constants,
591 const std::map<std::pair<IntegralType, int>,
592 std::pair<std::span<const T>, int>>& coefficients,
593 std::span<const std::int8_t> dof_marker0,
594 std::span<const std::int8_t> dof_marker1)
595
596{
597 common::Timer t_assm("[Assemble Matrix]");
598 using mdspanx3_t
599 = md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>>;
600
601 std::shared_ptr<const mesh::Mesh<U>> mesh = a.mesh();
602 assert(mesh);
603 std::span x = mesh->geometry().x();
604 impl::assemble_matrix<false>(mat_add, a,
605 mdspanx3_t(x.data(), x.size() / 3, 3), constants,
606 coefficients, dof_marker0, dof_marker1);
607}
608
619template <dolfinx::scalar T, std::floating_point U>
621 auto mat_add, const Form<T, U>& a,
622 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
623{
624 // Prepare constants and coefficients
625 const std::vector<T> constants = pack_constants(a);
626 auto coefficients = allocate_coefficient_storage(a);
627 pack_coefficients(a, coefficients);
628
629 std::array<std::vector<std::int8_t>, 2> markers;
630 auto [dof_marker0, dof_marker1] = impl::bc_dof_markers_pair(a, bcs, markers);
631
632 // Assemble
633 assemble_matrix(mat_add, a, std::span<const T>(constants),
634 make_coefficients_span(coefficients), dof_marker0,
635 dof_marker1);
636}
637
649template <dolfinx::scalar T, std::floating_point U>
650void assemble_matrix(auto mat_add, const Form<T, U>& a,
651 std::span<const std::int8_t> dof_marker0,
652 std::span<const std::int8_t> dof_marker1)
653
654{
655 // Prepare constants and coefficients
656 const std::vector<T> constants = pack_constants(a);
657 auto coefficients = allocate_coefficient_storage(a);
658 pack_coefficients(a, coefficients);
659
660 // Assemble
661 assemble_matrix(mat_add, a, std::span<const T>(constants),
662 make_coefficients_span(coefficients), dof_marker0,
663 dof_marker1);
664}
665
698template <dolfinx::scalar T, std::floating_point U>
700 auto set_fn, const FunctionSpace<U>& V,
701 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs,
702 T diagonal = T(1))
703{
704 logger().debug("Set diagonal");
705
706 std::vector<std::int32_t> rows;
707 for (auto& bc : bcs)
708 {
709 if (V.contains(*bc.get().function_space()))
710 {
711 const auto [dofs, range] = bc.get().dof_indices();
712 std::span<const std::int32_t> owned = dofs.first(range);
713 rows.insert(rows.end(), owned.begin(), owned.end());
714 }
715 }
716
717 // A condition's dofs are strictly increasing (a DirichletBC
718 // precondition), so one condition needs no sort. Several give sorted
719 // runs, which a comparison sort handles poorly and which are often
720 // already in order, hence the check before radix sorting.
721 if (!std::ranges::is_sorted(rows))
723
724 // Overlapping conditions can repeat a row
725 rows.erase(std::ranges::unique(rows).begin(), rows.end());
726 la::set_diagonal(set_fn, rows, diagonal);
727}
728
729} // namespace dolfinx::fem
std::pair< std::vector< std::vector< std::int8_t > >, std::vector< std::vector< T > > > bc_lifting_data(const std::vector< std::optional< std::reference_wrapper< const Form< T, U > > > > &a, const std::vector< std::vector< std::reference_wrapper< const DirichletBC< T, U > > > > &bcs1)
Constrained dof markers and boundary condition values on the trial space of each form in a,...
Definition assembler.h:235
std::array< std::span< const std::int8_t >, 2 > bc_dof_markers_pair(const Form< T, U > &a, const std::vector< std::reference_wrapper< const DirichletBC< T, U > > > &bcs, std::array< std::vector< std::int8_t >, 2 > &storage)
Mark the dofs of the test and trial spaces of a that the boundary conditions in bcs constrain.
Definition assembler.h:215
std::vector< std::int8_t > bc_dof_markers(const FunctionSpace< U > &V, const std::vector< std::reference_wrapper< const DirichletBC< T, U > > > &bcs)
Mark the dofs of V (owned and ghost, unrolled) constrained by the boundary conditions in bcs that are...
Definition assembler.h:174
Timer for measuring and logging elapsed time durations.
Definition Timer.h:41
Definition DirichletBC.h:261
A representation of finite element variational forms.
Definition Form.h:177
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
Common mesh for the form (the 'integration domain').
Definition Form.h:395
const std::vector< std::shared_ptr< const FunctionSpace< geometry_type > > > & function_spaces() const
Function spaces for all arguments.
Definition Form.h:403
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:36
bool contains(const FunctionSpace &V) const
Check whether V is subspace of this, or this itself.
Definition FunctionSpace.h:166
const std::vector< std::shared_ptr< const DofMap > > & dofmaps() const
The dofmaps.
Definition FunctionSpace.h:420
Matrix accumulate/set concept for functions that can be used in assemblers to accumulate or set value...
Definition utils.h:33
Definition types.h:29
Finite element method functionality.
Definition assemble_expression_impl.h:28
void assemble_matrix(la::MatSet< T > auto mat_add, const Form< T, U > &a, std::span< const T > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > &coefficients, std::span< const std::int8_t > dof_marker0, std::span< const std::int8_t > dof_marker1)
Assemble bilinear form into a matrix. Matrix must already be initialised. Does not zero or finalise t...
Definition assembler.h:588
T assemble_scalar(const Form< T, U > &M, std::span< const T > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > &coefficients)
Assemble functional into scalar.
Definition assembler.h:80
void set_diagonal(auto set_fn, const FunctionSpace< U > &V, const std::vector< std::reference_wrapper< const DirichletBC< T, U > > > &bcs, T diagonal=T(1))
Set a value on the diagonal of the locally owned rows that a Dirichlet boundary condition constrains.
Definition assembler.h:699
std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > make_coefficients_span(const std::map< std::pair< IntegralType, int >, std::pair< std::vector< T >, int > > &coeffs)
Create a map of std::spans from a map of std::vectors.
Definition assembler.h:54
void pack_coefficients(const Form< T, U > &form, std::map< std::pair< IntegralType, int >, std::pair< std::vector< T >, int > > &coeffs)
Pack coefficients of a Form.
Definition pack.h:267
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T, U > &form, IntegralType integral_type, int idx)
Allocate storage for coefficients of a pair (integral_type, idx) from a Form.
Definition pack.h:189
void assemble_vector(V &&b, const Form< T, U > &L, std::span< const T > constants, const std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > &coefficients)
Assemble linear form into a vector.
Definition assembler.h:140
void apply_lifting(V &&b, const std::vector< std::optional< std::reference_wrapper< const Form< T, U > > > > &a, const std::vector< std::span< const T > > &constants, const std::vector< std::map< std::pair< IntegralType, int >, std::pair< std::span< const T >, int > > > &coeffs, const std::vector< std::span< const std::int8_t > > &bc_markers1, const std::vector< std::span< const T > > &bc_values1, const std::vector< std::span< const T > > &x0, T alpha)
Modify the right-hand side vector to account for constraints (Dirichlet boundary condition constraint...
Definition assembler.h:311
std::vector< T > pack_constants(const std::vector< std::reference_wrapper< const fem::Constant< T > > > &c)
Pack constants of an Expression or Form into a single array ready for assembly.
Definition pack.h:459
void set_diagonal(MatSet< T > auto &&set_fn, const common::LocalIndexRange auto &rows, T diagonal=T(1))
Set a value on the diagonal of a matrix for specified rows.
Definition utils.h:51
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
constexpr void radix_sort(R &&range, P proj={})
Sort a range with radix sorting algorithm. The bucket size is determined by the number of bits to sor...
Definition sort.h:81
auto logger() -> spdlog::logger &
Dolfinx's logger.
Definition log.cpp:24
Functions supporting the packing of coefficient data.