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