DOLFINx 0.11.0.0
DOLFINx C++
Loading...
Searching...
No Matches
assembler.h
Go to the documentation of this file.
1// Copyright (C) 2018-2025 Garth N. Wells
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 "Function.h"
10#include "FunctionSpace.h"
11#include "assemble_expression_impl.h"
12#include "assemble_matrix_impl.h"
13#include "assemble_scalar_impl.h"
14#include "assemble_vector_impl.h"
15#include "pack.h"
16#include "traits.h"
17#include "utils.h"
18#include <algorithm>
19#include <basix/mdspan.hpp>
20#include <cstdint>
21#include <dolfinx/common/types.h>
22#include <memory>
23#include <optional>
24#include <span>
25#include <vector>
26
30
31namespace dolfinx::fem
32{
33template <dolfinx::scalar T, std::floating_point U>
34class DirichletBC;
35template <dolfinx::scalar T, std::floating_point U>
36class Expression;
37template <dolfinx::scalar T, std::floating_point U>
38class Form;
39template <std::floating_point T>
40class FunctionSpace;
41
63template <dolfinx::scalar T, std::floating_point U>
65 std::span<T> values, const fem::Expression<T, U>& e,
66 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
67 std::span<const T> constants, const mesh::Mesh<U>& mesh,
68 fem::MDSpan2 auto entities,
69 std::optional<
70 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
71 element)
72{
73 auto [X, Xshape] = e.X();
74 impl::tabulate_expression(values, e.kernel(), Xshape, e.value_size(), coeffs,
75 constants, mesh, entities, element);
76}
77
94template <dolfinx::scalar T, std::floating_point U>
95void tabulate_expression(std::span<T> values, const fem::Expression<T, U>& e,
96 const mesh::Mesh<U>& mesh, fem::MDSpan2 auto entities)
97{
98 std::optional<
99 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
100 element = std::nullopt;
101 if (auto V = e.argument_space(); V)
102 {
103 std::size_t num_argument_dofs
104 = V->dofmap()->element_dof_layout().num_dofs() * V->dofmap()->bs();
105 assert(V->element());
106 element = {std::cref(*V->element()), num_argument_dofs};
107 }
108
109 std::vector<int> coffsets = e.coefficient_offsets();
110 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
111 = e.coefficients();
112 std::vector<T> coeffs(entities.extent(0) * coffsets.back());
113 int cstride = coffsets.back();
114 {
115 std::vector<std::reference_wrapper<const Function<T, U>>> c;
116 std::ranges::transform(coefficients, std::back_inserter(c),
117 [](auto c) -> const Function<T, U>& { return *c; });
118 fem::pack_coefficients(c, coffsets, entities, std::span(coeffs));
119 }
120 std::vector<T> constants = fem::pack_constants(e);
121
123 values, e, md::mdspan(coeffs.data(), entities.size(), cstride),
124 std::span<const T>(constants), mesh, entities, element);
125}
126
127// -- Helper functions -----------------------------------------------------
128
130template <dolfinx::scalar T>
131std::map<std::pair<IntegralType, int>, std::pair<std::span<const T>, int>>
132make_coefficients_span(const std::map<std::pair<IntegralType, int>,
133 std::pair<std::vector<T>, int>>& coeffs)
134{
135 using Key = typename std::remove_reference_t<decltype(coeffs)>::key_type;
136 std::map<Key, std::pair<std::span<const T>, int>> c;
137 std::ranges::transform(
138 coeffs, std::inserter(c, c.end()),
139 [](auto& e) -> typename decltype(c)::value_type
140 { return {e.first, {e.second.first, e.second.second}}; });
141 return c;
142}
143
144// -- Scalar ----------------------------------------------------------------
145
157template <dolfinx::scalar T, std::floating_point U>
159 const Form<T, U>& M, std::span<const T> constants,
160 const std::map<std::pair<IntegralType, int>,
161 std::pair<std::span<const T>, int>>& coefficients)
162{
163 using mdspanx3_t
164 = md::mdspan<const scalar_value_t<T>,
165 md::extents<std::size_t, md::dynamic_extent, 3>>;
166
167 std::shared_ptr<const mesh::Mesh<U>> mesh = M.mesh();
168 assert(mesh);
169 std::span x = mesh->geometry().x();
170
171 // Accumulate contributions from each cell type
172 const int num_cell_types = mesh->topology()->cell_types().size();
173 T val = 0;
174 for (int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
175 {
176 // Geometry dofmap and data
177 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> x_dofmap
178 = mesh->geometry().dofmap(cell_type_idx);
179 if constexpr (std::is_same_v<U, scalar_value_t<T>>)
180 {
181 val += impl::assemble_scalar(M, x_dofmap,
182 mdspanx3_t(x.data(), x.size() / 3, 3),
183 constants, coefficients, cell_type_idx);
184 }
185 else
186 {
187 std::vector<scalar_value_t<T>> _x(x.begin(), x.end());
188 val += impl::assemble_scalar(M, x_dofmap,
189 mdspanx3_t(_x.data(), _x.size() / 3, 3),
190 constants, coefficients, cell_type_idx);
191 }
192 }
193 return val;
194}
195
203template <dolfinx::scalar T, std::floating_point U>
205{
206 const std::vector<T> constants = pack_constants(M);
207 auto coefficients = allocate_coefficient_storage(M);
208 pack_coefficients(M, coefficients);
209 return assemble_scalar(M, std::span(constants),
210 make_coefficients_span(coefficients));
211}
212
213// -- Vectors ----------------------------------------------------------------
214
225// template <dolfinx::scalar T, std::floating_point U>
226template <typename V, std::floating_point U,
227 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
228 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
230 V&& b, const Form<T, U>& L, std::span<const T> constants,
231 const std::map<std::pair<IntegralType, int>,
232 std::pair<std::span<const T>, int>>& coefficients)
233{
234 impl::assemble_vector(b, L, constants, coefficients);
235}
236
241// template <dolfinx::scalar T, std::floating_point U>
242// void assemble_vector(std::span<T> b, const Form<T, U>& L)
243template <typename V, std::floating_point U,
244 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
245 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
246void assemble_vector(V&& b, const Form<T, U>& L)
247{
248 auto coefficients = allocate_coefficient_storage(L);
249 pack_coefficients(L, coefficients);
250 const std::vector<T> constants = pack_constants(L);
251 assemble_vector(b, L, std::span(constants),
252 make_coefficients_span(coefficients));
253}
254
332template <typename V,
333 std::floating_point U
334 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
335 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
336 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
338 V&& b,
339 std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>> a,
340 const std::vector<std::span<const T>>& constants,
341 const std::vector<std::map<std::pair<IntegralType, int>,
342 std::pair<std::span<const T>, int>>>& coeffs,
343 const std::vector<
344 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
345 const std::vector<std::span<const T>>& x0, T alpha)
346{
347 // If all forms are null, there is nothing to do
348 if (std::ranges::all_of(a, [](auto ai) { return !ai; }))
349 return;
350
351 common::Timer t("[Apply lifting]");
352 impl::apply_lifting(b, a, constants, coeffs, bcs1, x0, alpha);
353}
354
383template <typename V,
384 std::floating_point U
385 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
386 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
387 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
389 V&& b,
390 std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>> a,
391 const std::vector<
392 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
393 const std::vector<std::span<const T>>& x0, T alpha)
394{
395 std::vector<
396 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>>>
397 coeffs;
398 std::vector<std::vector<T>> constants;
399 for (auto _a : a)
400 {
401 if (_a)
402 {
403 auto coefficients = allocate_coefficient_storage(_a->get());
404 pack_coefficients(_a->get(), coefficients);
405 coeffs.push_back(coefficients);
406 constants.push_back(pack_constants(_a->get()));
407 }
408 else
409 {
410 coeffs.emplace_back();
411 constants.emplace_back();
412 }
413 }
414
415 std::vector<std::span<const T>> _constants(constants.begin(),
416 constants.end());
417 std::vector<std::map<std::pair<IntegralType, int>,
418 std::pair<std::span<const T>, int>>>
419 _coeffs;
420 std::ranges::transform(coeffs, std::back_inserter(_coeffs),
421 [](auto& c) { return make_coefficients_span(c); });
422
423 apply_lifting(b, a, _constants, _coeffs, bcs1, x0, alpha);
424}
425
426// -- Matrices ---------------------------------------------------------------
427
445template <dolfinx::scalar T, std::floating_point U, bool LiftingMode = false>
447 la::MatSet<T> auto mat_add, const Form<T, U>& a,
448 std::span<const T> constants,
449 const std::map<std::pair<IntegralType, int>,
450 std::pair<std::span<const T>, int>>& coefficients,
451 std::span<const std::int8_t> dof_marker0,
452 std::span<const std::int8_t> dof_marker1)
453
454{
455 common::Timer t_assm("[Assemble Matrix]");
456 using mdspanx3_t
457 = md::mdspan<const scalar_value_t<T>,
458 md::extents<std::size_t, md::dynamic_extent, 3>>;
459
460 std::shared_ptr<const mesh::Mesh<U>> mesh = a.mesh();
461 assert(mesh);
462 std::span x = mesh->geometry().x();
463 if constexpr (std::is_same_v<U, scalar_value_t<T>>)
464 {
465 impl::assemble_matrix<T, U, LiftingMode>(
466 mat_add, a, mdspanx3_t(x.data(), x.size() / 3, 3), constants,
467 coefficients, dof_marker0, dof_marker1);
468 }
469 else
470 {
471 std::vector<scalar_value_t<T>> _x(x.begin(), x.end());
472 impl::assemble_matrix<T, U, LiftingMode>(
473 mat_add, a, mdspanx3_t(_x.data(), _x.size() / 3, 3), constants,
474 coefficients, dof_marker0, dof_marker1);
475 }
476}
477
485template <dolfinx::scalar T, std::floating_point U>
487 auto mat_add, const Form<T, U>& a, std::span<const T> constants,
488 const std::map<std::pair<IntegralType, int>,
489 std::pair<std::span<const T>, int>>& coefficients,
490 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
491{
492 // Index maps for dof ranges
493 // NOTE: For mixed-topology meshes, there will be multiple DOF maps,
494 // but the index maps are the same.
495 auto map0 = a.function_spaces().at(0)->dofmaps(0)->index_map;
496 auto map1 = a.function_spaces().at(1)->dofmaps(0)->index_map;
497 auto bs0 = a.function_spaces().at(0)->dofmaps(0)->index_map_bs();
498 auto bs1 = a.function_spaces().at(1)->dofmaps(0)->index_map_bs();
499
500 // Build dof markers
501 std::vector<std::int8_t> dof_marker0, dof_marker1;
502 assert(map0);
503 std::int32_t dim0 = bs0 * (map0->size_local() + map0->num_ghosts());
504 assert(map1);
505 std::int32_t dim1 = bs1 * (map1->size_local() + map1->num_ghosts());
506 for (std::size_t k = 0; k < bcs.size(); ++k)
507 {
508 assert(bcs[k].get().function_space());
509 if (a.function_spaces().at(0)->contains(*bcs[k].get().function_space()))
510 {
511 dof_marker0.resize(dim0, false);
512 bcs[k].get().mark_dofs(dof_marker0);
513 }
514
515 if (a.function_spaces().at(1)->contains(*bcs[k].get().function_space()))
516 {
517 dof_marker1.resize(dim1, false);
518 bcs[k].get().mark_dofs(dof_marker1);
519 }
520 }
521
522 // Assemble
523 assemble_matrix(mat_add, a, constants, coefficients, dof_marker0,
524 dof_marker1);
525}
526
532template <dolfinx::scalar T, std::floating_point U>
534 auto mat_add, const Form<T, U>& a,
535 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
536{
537 // Prepare constants and coefficients
538 const std::vector<T> constants = pack_constants(a);
539 auto coefficients = allocate_coefficient_storage(a);
540 pack_coefficients(a, coefficients);
541
542 // Assemble
543 assemble_matrix(mat_add, a, std::span(constants),
544 make_coefficients_span(coefficients), bcs);
545}
546
558template <dolfinx::scalar T, std::floating_point U>
559void assemble_matrix(auto mat_add, const Form<T, U>& a,
560 std::span<const std::int8_t> dof_marker0,
561 std::span<const std::int8_t> dof_marker1)
562
563{
564 // Prepare constants and coefficients
565 const std::vector<T> constants = pack_constants(a);
566 auto coefficients = allocate_coefficient_storage(a);
567 pack_coefficients(a, coefficients);
568
569 // Assemble
570 assemble_matrix(mat_add, a, std::span(constants),
571 make_coefficients_span(coefficients), dof_marker0,
572 dof_marker1);
573}
574
587template <dolfinx::scalar T>
588void set_diagonal(auto set_fn, std::span<const std::int32_t> rows,
589 T diagonal = 1.0)
590{
591 for (std::size_t i = 0; i < rows.size(); ++i)
592 {
593 std::span diag_span(&diagonal, 1);
594 set_fn(rows.subspan(i, 1), rows.subspan(i, 1), diag_span);
595 }
596}
597
614template <dolfinx::scalar T, std::floating_point U>
616 auto set_fn, const FunctionSpace<U>& V,
617 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs,
618 T diagonal = 1.0)
619{
620 spdlog::debug("Set diagonal");
621 for (auto& bc : bcs)
622 {
623 if (V.contains(*bc.get().function_space()))
624 {
625 const auto [dofs, range] = bc.get().dof_indices();
626 set_diagonal(set_fn, dofs.first(range), diagonal);
627 }
628 }
629}
630
631} // namespace dolfinx::fem
Timer for measuring and logging elapsed time durations.
Definition Timer.h:40
Definition DirichletBC.h:258
An Expression represents a mathematical expression evaluated at a pre-defined points on a reference c...
Definition Expression.h:41
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > X() const
Evaluation point coordinates on the reference cell.
Definition Expression.h:166
const std::vector< std::shared_ptr< const Function< scalar_type, geometry_type > > > & coefficients() const
Expression coefficients.
Definition Expression.h:115
std::shared_ptr< const FunctionSpace< geometry_type > > argument_space() const
Argument function space.
Definition Expression.h:106
const std::function< void(scalar_type *, const scalar_type *, const scalar_type *, const geometry_type *, const int *, const uint8_t *, void *)> & kernel() const
Function for tabulating the Expression.
Definition Expression.h:150
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Expression.h:134
int value_size() const
Value size of the Expression result.
Definition Expression.h:156
Model of a finite element.
Definition FiniteElement.h:57
A representation of finite element variational forms.
Definition Form.h:117
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
Common mesh for the form (the 'integration domain').
Definition Form.h:362
const std::vector< std::shared_ptr< const FunctionSpace< geometry_type > > > & function_spaces() const
Function spaces for all arguments.
Definition Form.h:370
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:34
bool contains(const FunctionSpace &V) const
Check whether V is subspace of this, or this itself.
Definition FunctionSpace.h:153
Definition Function.h:47
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Concept for mdspan of rank 1 or 2.
Definition traits.h:36
Matrix accumulate/set concept for functions that can be used in assemblers to accumulate or set value...
Definition utils.h:28
Definition types.h:26
Functions supporting finite element method operations.
Finite element method functionality.
Definition assemble_expression_impl.h:23
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 pack.h:170
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:158
void set_diagonal(auto set_fn, std::span< const std::int32_t > rows, T diagonal=1.0)
Sets a value to the diagonal of a matrix for specified rows.
Definition assembler.h:588
void tabulate_expression(std::span< T > values, const fem::Expression< T, U > &e, md::mdspan< const T, md::dextents< std::size_t, 2 > > coeffs, std::span< const T > constants, const mesh::Mesh< U > &mesh, fem::MDSpan2 auto entities, std::optional< std::pair< std::reference_wrapper< const FiniteElement< U > >, std::size_t > > element)
Evaluate an Expression on cells or facets.
Definition assembler.h:64
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:132
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:229
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:222
std::vector< T > pack_constants(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:378
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:446
void apply_lifting(V &&b, 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::vector< std::reference_wrapper< const DirichletBC< T, U > > > > &bcs1, 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:337
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
Functions supporting the packing of coefficient data.