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 "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 <dolfinx/mesh/EntityMap.h>
23#include <memory>
24#include <optional>
25#include <span>
26#include <stdexcept>
27#include <utility>
28#include <vector>
29
33
34namespace dolfinx::fem
35{
36template <dolfinx::scalar T, std::floating_point U>
37class DirichletBC;
38template <dolfinx::scalar T, std::floating_point U>
39class Expression;
40template <dolfinx::scalar T, std::floating_point U>
41class Form;
42template <std::floating_point T>
43class FunctionSpace;
44
66template <dolfinx::scalar T, std::floating_point U>
68 std::span<T> values, const fem::Expression<T, U>& e,
69 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
70 std::span<const T> constants, const mesh::Mesh<U>& mesh,
71 fem::MDSpan2 auto entities,
72 std::optional<
73 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
74 element)
75{
76 // Check that domain is the same as mesh of the expression
77 if (e.coordinate_element_hash() != mesh.geometry().cmaps().front().hash())
78 {
79 throw std::invalid_argument(
80 "Expression was created on a different mesh. Cannot tabulate.");
81 }
82 auto [X, Xshape] = e.X();
83 impl::tabulate_expression(values, e.kernel(), Xshape, e.value_size(), coeffs,
84 constants, mesh, entities, element);
85}
86
103template <dolfinx::scalar T, std::floating_point U>
104void tabulate_expression(std::span<T> values, const fem::Expression<T, U>& e,
105 const mesh::Mesh<U>& mesh, fem::MDSpan2 auto entities)
106{
107 // Check that domain is the same as mesh of the expression
108 if (e.coordinate_element_hash() != mesh.geometry().cmaps().front().hash())
109 {
110 throw std::invalid_argument(
111 "Expression was created on a different mesh. Cannot tabulate.");
112 }
113
114 std::optional<
115 std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
116 element = std::nullopt;
117 if (auto V = e.argument_space(); V)
118 {
119 std::size_t num_argument_dofs
120 = V->dofmap()->element_dof_layout().num_dofs() * V->dofmap()->bs();
121 assert(V->element());
122 element = {std::cref(*V->element()), num_argument_dofs};
123 }
124
125 std::vector<int> coffsets = e.coefficient_offsets();
126 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
127 = e.coefficients();
128 std::vector<T> coeffs(entities.extent(0) * coffsets.back());
129 int cstride = coffsets.back();
130 {
131 std::vector<std::reference_wrapper<const Function<T, U>>> c;
132 std::ranges::transform(coefficients, std::back_inserter(c),
133 [](auto c) -> const Function<T, U>& { return *c; });
134 fem::pack_coefficients(c, mesh, entities, e.entity_maps(), coffsets,
135 std::span(coeffs));
136 }
137 std::vector<T> constants = fem::pack_constants(e);
138
140 values, e,
141 md::mdspan(std::as_const(coeffs).data(), entities.extent(0), cstride),
142 std::span<const T>(constants), mesh, entities, element);
143}
144
145// -- Helper functions -----------------------------------------------------
146
148template <dolfinx::scalar T>
149std::map<std::pair<IntegralType, int>, std::pair<std::span<const T>, int>>
150make_coefficients_span(const std::map<std::pair<IntegralType, int>,
151 std::pair<std::vector<T>, int>>& coeffs)
152{
153 using Key = typename std::remove_reference_t<decltype(coeffs)>::key_type;
154 std::map<Key, std::pair<std::span<const T>, int>> c;
155 std::ranges::transform(
156 coeffs, std::inserter(c, c.end()),
157 [](auto& e) -> typename decltype(c)::value_type
158 { return {e.first, {e.second.first, e.second.second}}; });
159 return c;
160}
161
162// -- Scalar ----------------------------------------------------------------
163
175template <dolfinx::scalar T, std::floating_point U>
177 const Form<T, U>& M, std::span<const T> constants,
178 const std::map<std::pair<IntegralType, int>,
179 std::pair<std::span<const T>, int>>& coefficients)
180{
181 using mdspanx3_t
182 = md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>>;
183
184 std::shared_ptr<const mesh::Mesh<U>> mesh = M.mesh();
185 assert(mesh);
186 std::span x = mesh->geometry().x();
187
188 // Accumulate contributions from each cell type
189 const int num_cell_types = mesh->topology()->cell_types().size();
190 T val = 0;
191 for (int cell_type_idx = 0; cell_type_idx < num_cell_types; ++cell_type_idx)
192 {
193 // Geometry dofmap and data
194 md::mdspan<const std::int32_t, md::dextents<std::size_t, 2>> x_dofmap
195 = mesh->geometry().dofmaps().at(cell_type_idx);
196 val += impl::assemble_scalar(M, x_dofmap,
197 mdspanx3_t(x.data(), x.size() / 3, 3),
198 constants, coefficients, cell_type_idx);
199 }
200 return val;
201}
202
210template <dolfinx::scalar T, std::floating_point U>
212{
213 const std::vector<T> constants = pack_constants(M);
214 auto coefficients = allocate_coefficient_storage(M);
215 pack_coefficients(M, coefficients);
216 return assemble_scalar(M, std::span(constants),
217 make_coefficients_span(coefficients));
218}
219
220// -- Vectors ----------------------------------------------------------------
221
232// template <dolfinx::scalar T, std::floating_point U>
233template <typename V, std::floating_point U,
234 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
235 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
237 V&& b, const Form<T, U>& L, std::span<const T> constants,
238 const std::map<std::pair<IntegralType, int>,
239 std::pair<std::span<const T>, int>>& coefficients)
240{
241 impl::assemble_vector(b, L, constants, coefficients);
242}
243
248// template <dolfinx::scalar T, std::floating_point U>
249// void assemble_vector(std::span<T> b, const Form<T, U>& L)
250template <typename V, std::floating_point U,
251 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
252 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
253void assemble_vector(V&& b, const Form<T, U>& L)
254{
255 auto coefficients = allocate_coefficient_storage(L);
256 pack_coefficients(L, coefficients);
257 const std::vector<T> constants = pack_constants(L);
258 assemble_vector(b, L, std::span(constants),
259 make_coefficients_span(coefficients));
260}
261
339template <typename V,
340 std::floating_point U
341 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
342 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
343 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
345 V&& b,
346 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
347 a,
348 const std::vector<std::span<const T>>& constants,
349 const std::vector<std::map<std::pair<IntegralType, int>,
350 std::pair<std::span<const T>, int>>>& coeffs,
351 const std::vector<
352 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
353 const std::vector<std::span<const T>>& x0, T alpha)
354{
355 // If all forms are null, there is nothing to do
356 if (std::ranges::all_of(a, [](auto ai) { return !ai; }))
357 return;
358
359 common::Timer t("[Apply lifting]");
360
361 if (!x0.empty() and x0.size() != a.size())
362 {
363 throw std::invalid_argument(
364 "Mismatch in size between x0 and bilinear form in assembler.");
365 }
366
367 if (a.size() != bcs1.size())
368 {
369 throw std::invalid_argument(
370 "Mismatch in size between a and bcs in assembler.");
371 }
372
373 // Reused across iterations so `assign` below can recycle the
374 // existing buffer instead of reallocating for every block.
375 std::vector<std::int8_t> bc_markers1;
376 std::vector<T> bc_values1;
377 for (std::size_t j = 0; j < a.size(); ++j)
378 {
379 if (a[j] and !bcs1[j].empty())
380 {
381 assert(a[j]->get().function_spaces().at(0));
382 auto V1 = a[j]->get().function_spaces()[1];
383 assert(V1);
384
385 const int bs0 = a[j]->get().function_spaces()[0]->dofmaps().front()->bs();
386 const int bs1 = V1->dofmaps().front()->bs();
387
388 std::span<const T> _x0;
389 if (!x0.empty())
390 _x0 = x0[j];
391
392 std::shared_ptr<const DofMap> dofmap = V1->dofmaps().front();
393 auto map1 = dofmap->index_map;
394 const int map_bs1 = dofmap->index_map_bs();
395 assert(map1);
396 const int crange = map_bs1 * (map1->size_local() + map1->num_ghosts());
397 bc_markers1.assign(crange, false);
398 bc_values1.assign(crange, 0);
399 for (auto& bc : bcs1[j])
400 {
401 bc.get().mark_dofs(bc_markers1);
402 bc.get().set(bc_values1, std::nullopt, 1);
403 }
404
405 if (bs0 == 1 and bs1 == 1)
406 {
407 impl::lift_bc(b, a[j]->get(), std::integral_constant<int, 1>{},
408 std::integral_constant<int, 1>{}, constants[j], coeffs[j],
409 std::span<const T>(bc_values1), bc_markers1, _x0, alpha);
410 }
411 else if (bs0 == 3 and bs1 == 3)
412 {
413 impl::lift_bc(b, a[j]->get(), std::integral_constant<int, 3>{},
414 std::integral_constant<int, 3>{}, constants[j], coeffs[j],
415 std::span<const T>(bc_values1), bc_markers1, _x0, alpha);
416 }
417 else
418 {
419 impl::lift_bc(b, a[j]->get(), bs0, bs1, constants[j], coeffs[j],
420 std::span<const T>(bc_values1), bc_markers1, _x0, alpha);
421 }
422 }
423 }
424}
425
454template <typename V,
455 std::floating_point U
456 = scalar_value_t<typename std::remove_cvref_t<V>::value_type>,
457 dolfinx::scalar T = typename std::remove_cvref_t<V>::value_type>
458 requires std::is_same_v<typename std::remove_cvref_t<V>::value_type, T>
460 V&& b,
461 const std::vector<std::optional<std::reference_wrapper<const Form<T, U>>>>&
462 a,
463 const std::vector<
464 std::vector<std::reference_wrapper<const DirichletBC<T, U>>>>& bcs1,
465 const std::vector<std::span<const T>>& x0, T alpha)
466{
467 std::vector<
468 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>>>
469 coeffs;
470 std::vector<std::vector<T>> constants;
471 for (const auto& _a : a)
472 {
473 if (_a)
474 {
475 auto coefficients = allocate_coefficient_storage(_a->get());
476 pack_coefficients(_a->get(), coefficients);
477 coeffs.push_back(coefficients);
478 constants.push_back(pack_constants(_a->get()));
479 }
480 else
481 {
482 coeffs.emplace_back();
483 constants.emplace_back();
484 }
485 }
486
487 std::vector<std::span<const T>> _constants(constants.begin(),
488 constants.end());
489 std::vector<std::map<std::pair<IntegralType, int>,
490 std::pair<std::span<const T>, int>>>
491 _coeffs;
492 std::ranges::transform(coeffs, std::back_inserter(_coeffs),
493 [](auto& c) { return make_coefficients_span(c); });
494
495 apply_lifting(b, a, _constants, _coeffs, bcs1, x0, alpha);
496}
497
498// -- Matrices ---------------------------------------------------------------
499
516template <dolfinx::scalar T, std::floating_point U>
518 la::MatSet<T> auto mat_add, const Form<T, U>& a,
519 std::span<const T> constants,
520 const std::map<std::pair<IntegralType, int>,
521 std::pair<std::span<const T>, int>>& coefficients,
522 std::span<const std::int8_t> dof_marker0,
523 std::span<const std::int8_t> dof_marker1)
524
525{
526 common::Timer t_assm("[Assemble Matrix]");
527 using mdspanx3_t
528 = md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>>;
529
530 std::shared_ptr<const mesh::Mesh<U>> mesh = a.mesh();
531 assert(mesh);
532 std::span x = mesh->geometry().x();
533 impl::assemble_matrix<false>(mat_add, a,
534 mdspanx3_t(x.data(), x.size() / 3, 3), constants,
535 coefficients, dof_marker0, dof_marker1);
536}
537
545template <dolfinx::scalar T, std::floating_point U>
547 auto mat_add, const Form<T, U>& a, std::span<const T> constants,
548 const std::map<std::pair<IntegralType, int>,
549 std::pair<std::span<const T>, int>>& coefficients,
550 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
551{
552 // Index maps for dof ranges
553 // NOTE: For mixed-topology meshes, there will be multiple DOF maps,
554 // but the index maps are the same.
555 auto map0 = a.function_spaces().at(0)->dofmaps().front()->index_map;
556 auto map1 = a.function_spaces().at(1)->dofmaps().front()->index_map;
557 auto bs0 = a.function_spaces().at(0)->dofmaps().front()->index_map_bs();
558 auto bs1 = a.function_spaces().at(1)->dofmaps().front()->index_map_bs();
559
560 // Build dof markers
561 std::vector<std::int8_t> dof_marker0, dof_marker1;
562 assert(map0);
563 std::int32_t dim0 = bs0 * (map0->size_local() + map0->num_ghosts());
564 assert(map1);
565 std::int32_t dim1 = bs1 * (map1->size_local() + map1->num_ghosts());
566 for (std::size_t k = 0; k < bcs.size(); ++k)
567 {
568 assert(bcs[k].get().function_space());
569 if (a.function_spaces().at(0)->contains(*bcs[k].get().function_space()))
570 {
571 dof_marker0.resize(dim0, false);
572 bcs[k].get().mark_dofs(dof_marker0);
573 }
574
575 if (a.function_spaces().at(1)->contains(*bcs[k].get().function_space()))
576 {
577 dof_marker1.resize(dim1, false);
578 bcs[k].get().mark_dofs(dof_marker1);
579 }
580 }
581
582 // Assemble
583 fem::assemble_matrix(mat_add, a, constants, coefficients, dof_marker0,
584 dof_marker1);
585}
586
592template <dolfinx::scalar T, std::floating_point U>
594 auto mat_add, const Form<T, U>& a,
595 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs)
596{
597 // Prepare constants and coefficients
598 const std::vector<T> constants = pack_constants(a);
599 auto coefficients = allocate_coefficient_storage(a);
600 pack_coefficients(a, coefficients);
601
602 // Assemble
603 assemble_matrix(mat_add, a, std::span(constants),
604 make_coefficients_span(coefficients), bcs);
605}
606
618template <dolfinx::scalar T, std::floating_point U>
619void assemble_matrix(auto mat_add, const Form<T, U>& a,
620 std::span<const std::int8_t> dof_marker0,
621 std::span<const std::int8_t> dof_marker1)
622
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 // Assemble
630 impl::assemble_matrix<false>(mat_add, a, std::span(constants),
631 make_coefficients_span(coefficients),
632 dof_marker0, dof_marker1);
633}
634
647template <dolfinx::scalar T>
648void set_diagonal(auto set_fn, std::span<const std::int32_t> rows,
649 T diagonal = 1.0)
650{
651 for (std::size_t i = 0; i < rows.size(); ++i)
652 {
653 std::span diag_span(&diagonal, 1);
654 set_fn(rows.subspan(i, 1), rows.subspan(i, 1), diag_span);
655 }
656}
657
674template <dolfinx::scalar T, std::floating_point U>
676 auto set_fn, const FunctionSpace<U>& V,
677 const std::vector<std::reference_wrapper<const DirichletBC<T, U>>>& bcs,
678 T diagonal = 1.0)
679{
680 spdlog::debug("Set diagonal");
681 for (auto& bc : bcs)
682 {
683 if (V.contains(*bc.get().function_space()))
684 {
685 const auto [dofs, range] = bc.get().dof_indices();
686 set_diagonal(set_fn, dofs.first(range), diagonal);
687 }
688 }
689}
690
691} // namespace dolfinx::fem
Timer for measuring and logging elapsed time durations.
Definition Timer.h:41
Definition DirichletBC.h:259
An Expression represents a mathematical expression evaluated at a pre-defined points on a reference c...
Definition Expression.h:43
std::pair< std::vector< geometry_type >, std::array< std::size_t, 2 > > X() const
Evaluation point coordinates on the reference cell.
Definition Expression.h:174
const std::vector< std::shared_ptr< const Function< scalar_type, geometry_type > > > & coefficients() const
Expression coefficients.
Definition Expression.h:123
std::shared_ptr< const FunctionSpace< geometry_type > > argument_space() const
Argument function space.
Definition Expression.h:114
std::uint64_t coordinate_element_hash() const
Hash for coordinate element used to create the expression.
Definition Expression.h:187
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:158
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Expression.h:142
int value_size() const
Value size of the Expression result.
Definition Expression.h:164
const std::vector< std::reference_wrapper< const dolfinx::mesh::EntityMap > > & entity_maps() const
Maps between entities of different meshes.
Definition Expression.h:181
Model of a finite element.
Definition FiniteElement.h:199
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:459
const std::vector< std::shared_ptr< const FunctionSpace< geometry_type > > > & function_spaces() const
Function spaces for all arguments.
Definition Form.h:467
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:35
bool contains(const FunctionSpace &V) const
Check whether V is subspace of this, or this itself.
Definition FunctionSpace.h:154
Definition Function.h:48
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
Concept for mdspan of rank 1 or 2.
Definition traits.h:52
Matrix accumulate/set concept for functions that can be used in assemblers to accumulate or set value...
Definition utils.h:28
Definition types.h:27
Functions supporting finite element method operations.
Finite element method functionality.
Definition assemble_expression_impl.h:24
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:517
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:176
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:648
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:67
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:150
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:259
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:181
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::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:344
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:236
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:573
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
Functions supporting the packing of coefficient data.