DOLFINx 0.10.0.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
assemble_scalar_impl.h
1// Copyright (C) 2019-2025 Garth N. Wells and Paul T. Kühner
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 "Constant.h"
10#include "Form.h"
11#include "FunctionSpace.h"
12#include "utils.h"
13#include <algorithm>
14#include <basix/mdspan.hpp>
15#include <dolfinx/common/IndexMap.h>
16#include <dolfinx/mesh/Geometry.h>
17#include <dolfinx/mesh/Mesh.h>
18#include <dolfinx/mesh/Topology.h>
19#include <memory>
20#include <vector>
21
22namespace dolfinx::fem::impl
23{
25template <dolfinx::scalar T>
26T assemble_cells(mdspan2_t x_dofmap,
27 md::mdspan<const scalar_value_t<T>,
28 md::extents<std::size_t, md::dynamic_extent, 3>>
29 x,
30 std::span<const std::int32_t> cells, FEkernel<T> auto fn,
31 std::span<const T> constants,
32 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
33 std::span<scalar_value_t<T>> cdofs_b)
34{
35 T value(0);
36 if (cells.empty())
37 return value;
38
39 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
40
41 // Iterate over all cells
42 for (std::size_t index = 0; index < cells.size(); ++index)
43 {
44 std::int32_t c = cells[index];
45
46 // Get cell coordinates/geometry
47 auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
48 for (std::size_t i = 0; i < x_dofs.size(); ++i)
49 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs_b.begin(), 3 * i));
50
51 fn(&value, &coeffs(index, 0), constants.data(), cdofs_b.data(), nullptr,
52 nullptr, nullptr);
53 }
54
55 return value;
56}
57
59template <dolfinx::scalar T>
60T assemble_exterior_facets(
61 mdspan2_t x_dofmap,
62 md::mdspan<const scalar_value_t<T>,
63 md::extents<std::size_t, md::dynamic_extent, 3>>
64 x,
65 md::mdspan<const std::int32_t,
66 md::extents<std::size_t, md::dynamic_extent, 2>>
67 facets,
68 FEkernel<T> auto fn, std::span<const T> constants,
69 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
70 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms,
71 std::span<scalar_value_t<T>> cdofs_b)
72{
73 T value(0);
74 if (facets.empty())
75 return value;
76
77 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
78
79 // Iterate over all facets
80 for (std::size_t f = 0; f < facets.extent(0); ++f)
81 {
82 std::int32_t cell = facets(f, 0);
83 std::int32_t local_facet = facets(f, 1);
84
85 // Get cell coordinates/geometry
86 auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
87 for (std::size_t i = 0; i < x_dofs.size(); ++i)
88 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs_b.begin(), 3 * i));
89
90 // Permutations
91 std::uint8_t perm = perms.empty() ? 0 : perms(cell, local_facet);
92 fn(&value, &coeffs(f, 0), constants.data(), cdofs_b.data(), &local_facet,
93 &perm, nullptr);
94 }
95
96 return value;
97}
98
100template <dolfinx::scalar T>
101T assemble_interior_facets(
102 mdspan2_t x_dofmap,
103 md::mdspan<const scalar_value_t<T>,
104 md::extents<std::size_t, md::dynamic_extent, 3>>
105 x,
106 md::mdspan<const std::int32_t,
107 md::extents<std::size_t, md::dynamic_extent, 2, 2>>
108 facets,
109 FEkernel<T> auto fn, std::span<const T> constants,
110 md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
111 md::dynamic_extent>>
112 coeffs,
113 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms,
114 std::span<scalar_value_t<T>> cdofs_b)
115{
116 T value(0);
117 if (facets.empty())
118 return value;
119
120 // Create data structures used in assembly
121 assert(cdofs_b.size() >= 2 * 3 * x_dofmap.extent(1));
122 auto cdofs0 = cdofs_b.first(3 * x_dofmap.extent(1));
123 auto cdofs1 = cdofs_b.last(3 * x_dofmap.extent(1));
124
125 // Iterate over all facets
126 for (std::size_t f = 0; f < facets.extent(0); ++f)
127 {
128 std::array cells = {facets(f, 0, 0), facets(f, 1, 0)};
129 std::array local_facet = {facets(f, 0, 1), facets(f, 1, 1)};
130
131 // Get cell geometry
132 auto x_dofs0 = md::submdspan(x_dofmap, cells[0], md::full_extent);
133 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
134 std::copy_n(&x(x_dofs0[i], 0), 3, std::next(cdofs0.begin(), 3 * i));
135 auto x_dofs1 = md::submdspan(x_dofmap, cells[1], md::full_extent);
136 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
137 std::copy_n(&x(x_dofs1[i], 0), 3, std::next(cdofs1.begin(), 3 * i));
138
139 std::array perm = perms.empty()
140 ? std::array<std::uint8_t, 2>{0, 0}
141 : std::array{perms(cells[0], local_facet[0]),
142 perms(cells[1], local_facet[1])};
143 fn(&value, &coeffs(f, 0, 0), constants.data(), cdofs_b.data(),
144 local_facet.data(), perm.data(), nullptr);
145 }
146
147 return value;
148}
149
151template <dolfinx::scalar T>
152T assemble_vertices(mdspan2_t x_dofmap,
153 md::mdspan<const scalar_value_t<T>,
154 md::extents<std::size_t, md::dynamic_extent, 3>>
155 x,
156 md::mdspan<const std::int32_t,
157 md::extents<std::size_t, md::dynamic_extent, 2>>
158 vertices,
159 FEkernel<T> auto fn, std::span<const T> constants,
160 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
161 std::span<scalar_value_t<T>> cdofs_b)
162{
163 T value(0);
164 if (vertices.empty())
165 return value;
166
167 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
168
169 // Iterate over all cells
170 for (std::size_t index = 0; index < vertices.extent(0); ++index)
171 {
172 std::int32_t cell = vertices(index, 0);
173 std::int32_t local_vertex_index = vertices(index, 1);
174
175 // Get cell coordinates/geometry
176 auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
177 for (std::size_t i = 0; i < x_dofs.size(); ++i)
178 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs_b.begin(), 3 * i));
179
180 fn(&value, &coeffs(index, 0), constants.data(), cdofs_b.data(),
181 &local_vertex_index, nullptr, nullptr);
182 }
183
184 return value;
185}
186
188template <dolfinx::scalar T, std::floating_point U>
189T assemble_scalar(
190 const fem::Form<T, U>& M, mdspan2_t x_dofmap,
191 md::mdspan<const scalar_value_t<T>,
192 md::extents<std::size_t, md::dynamic_extent, 3>>
193 x,
194 std::span<const T> constants,
195 const std::map<std::pair<IntegralType, int>,
196 std::pair<std::span<const T>, int>>& coefficients)
197{
198 std::shared_ptr<const mesh::Mesh<U>> mesh = M.mesh();
199 assert(mesh);
200
201 std::vector<scalar_value_t<T>> cdofs_b(2 * 3 * x_dofmap.extent(1));
202
203 T value = 0;
204 for (int i = 0; i < M.num_integrals(IntegralType::cell, 0); ++i)
205 {
206 auto fn = M.kernel(IntegralType::cell, i, 0);
207 assert(fn);
208 auto& [coeffs, cstride] = coefficients.at({IntegralType::cell, i});
209 std::span<const std::int32_t> cells = M.domain(IntegralType::cell, i, 0);
210 assert(cells.size() * cstride == coeffs.size());
211 value += impl::assemble_cells(
212 x_dofmap, x, cells, fn, constants,
213 md::mdspan(coeffs.data(), cells.size(), cstride), cdofs_b);
214 }
215
216 mesh::CellType cell_type = mesh->topology()->cell_type();
217 int num_facets_per_cell
218 = mesh::cell_num_entities(cell_type, mesh->topology()->dim() - 1);
219 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms;
220 if (M.needs_facet_permutations())
221 {
222 mesh->topology_mutable()->create_entity_permutations();
223 const std::vector<std::uint8_t>& p
224 = mesh->topology()->get_facet_permutations();
225 perms = md::mdspan(p.data(), p.size() / num_facets_per_cell,
226 num_facets_per_cell);
227 }
228
229 for (int i = 0; i < M.num_integrals(IntegralType::exterior_facet, 0); ++i)
230 {
231 auto fn = M.kernel(IntegralType::exterior_facet, i, 0);
232 assert(fn);
233 auto& [coeffs, cstride]
234 = coefficients.at({IntegralType::exterior_facet, i});
235
236 std::span facets = M.domain(IntegralType::exterior_facet, i, 0);
237
238 // Two values per each adjacent cell (cell index and local facet
239 // index)
240 constexpr std::size_t num_adjacent_cells = 1;
241 constexpr std::size_t shape1 = 2 * num_adjacent_cells;
242
243 assert((facets.size() / 2) * cstride == coeffs.size());
244 value += impl::assemble_exterior_facets(
245 x_dofmap, x,
246 md::mdspan<const std::int32_t,
247 md::extents<std::size_t, md::dynamic_extent, 2>>(
248 facets.data(), facets.size() / shape1, 2),
249 fn, constants,
250 md::mdspan(coeffs.data(), facets.size() / shape1, cstride), perms,
251 cdofs_b);
252 }
253
254 for (int i = 0; i < M.num_integrals(IntegralType::interior_facet, 0); ++i)
255 {
256 auto fn = M.kernel(IntegralType::interior_facet, i, 0);
257 assert(fn);
258 auto& [coeffs, cstride]
259 = coefficients.at({IntegralType::interior_facet, i});
260 std::span facets = M.domain(IntegralType::interior_facet, i, 0);
261
262 constexpr std::size_t num_adjacent_cells = 2;
263 // Two values per each adj. cell (cell index and local facet index).
264 constexpr std::size_t shape1 = 2 * num_adjacent_cells;
265
266 assert((facets.size() / shape1) * 2 * cstride == coeffs.size());
267 value += impl::assemble_interior_facets(
268 x_dofmap, x,
269 md::mdspan<const std::int32_t,
270 md::extents<std::size_t, md::dynamic_extent, 2, 2>>(
271 facets.data(), facets.size() / shape1, 2, 2),
272 fn, constants,
273 md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
274 md::dynamic_extent>>(
275 coeffs.data(), facets.size() / shape1, 2, cstride),
276 perms, cdofs_b);
277 }
278
279 for (int i = 0; i < M.num_integrals(IntegralType::vertex, 0); ++i)
280 {
281 auto fn = M.kernel(IntegralType::vertex, i, 0);
282 assert(fn);
283
284 auto& [coeffs, cstride] = coefficients.at({IntegralType::vertex, i});
285
286 std::span<const std::int32_t> vertices
287 = M.domain(IntegralType::vertex, i, 0);
288 assert(vertices.size() * cstride == coeffs.size());
289
290 constexpr std::size_t num_adjacent_cells = 1;
291 // Two values per adj. cell (cell index and local vertex index).
292 constexpr std::size_t shape1 = 2 * num_adjacent_cells;
293
294 value += impl::assemble_vertices(
295 x_dofmap, x,
296 md::mdspan<const std::int32_t,
297 md::extents<std::size_t, md::dynamic_extent, 2>>(
298 vertices.data(), vertices.size() / shape1, shape1),
299 fn, constants,
300 md::mdspan(coeffs.data(), vertices.size() / shape1, cstride), cdofs_b);
301 }
302
303 return value;
304}
305
306} // namespace dolfinx::fem::impl
Functions supporting finite element method operations.
void cells(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:16
@ vertex
Vertex.
Definition Form.h:43
@ interior_facet
Interior facet.
Definition Form.h:42
@ cell
Cell.
Definition Form.h:40
@ exterior_facet
Exterior facet.
Definition Form.h:41
CellType
Cell type identifier.
Definition cell_types.h:22
int cell_num_entities(CellType type, int dim)
Definition cell_types.cpp:139