DOLFINx 0.12.0.0
DOLFINx C++
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 <type_traits>
21#include <vector>
22
23namespace dolfinx::fem::impl
24{
31template <dolfinx::scalar T, std::floating_point U>
32T assemble_cells(
33 mdspan2_t x_dofmap,
34 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
35 std::span<const std::int32_t> cells, const FEkernel<T, U> auto& fn,
36 std::span<const T> constants,
37 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
38 std::span<std::type_identity_t<U>> cdofs_b)
39{
40 T value(0);
41 if (cells.empty())
42 return value;
43
44 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
45
46 // Iterate over all cells
47 for (std::size_t index = 0; index < cells.size(); ++index)
48 {
49 std::int32_t c = cells[index];
50
51 // Get cell coordinates/geometry
52 auto x_dofs = md::submdspan(x_dofmap, c, md::full_extent);
53 for (std::size_t i = 0; i < x_dofs.size(); ++i)
54 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs_b.begin(), 3 * i));
55
56 fn(&value, &coeffs(index, 0), constants.data(), cdofs_b.data(), nullptr,
57 nullptr, nullptr);
58 }
59
60 return value;
61}
62
78template <dolfinx::scalar T, std::floating_point U>
79T assemble_entities(
80 mdspan2_t x_dofmap,
81 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
82 md::mdspan<const std::int32_t,
83 md::extents<std::size_t, md::dynamic_extent, 2>>
84 entities,
85 const FEkernel<T, U> auto& fn, std::span<const T> constants,
86 md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
87 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms,
88 std::span<std::type_identity_t<U>> cdofs_b)
89{
90 T value(0);
91 if (entities.empty())
92 return value;
93
94 assert(cdofs_b.size() >= 3 * x_dofmap.extent(1));
95
96 // Iterate over all facets
97 for (std::size_t f = 0; f < entities.extent(0); ++f)
98 {
99 std::int32_t cell = entities(f, 0);
100 std::int32_t local_entity = entities(f, 1);
101
102 // Get cell coordinates/geometry
103 auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
104 for (std::size_t i = 0; i < x_dofs.size(); ++i)
105 std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs_b.begin(), 3 * i));
106
107 // Permutations
108 std::uint8_t perm = perms.empty() ? 0 : perms(cell, local_entity);
109 fn(&value, &coeffs(f, 0), constants.data(), cdofs_b.data(), &local_entity,
110 &perm, nullptr);
111 }
112
113 return value;
114}
115
122template <dolfinx::scalar T, std::floating_point U>
123T assemble_interior_facets(
124 mdspan2_t x_dofmap,
125 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
126 md::mdspan<const std::int32_t,
127 md::extents<std::size_t, md::dynamic_extent, 2, 2>>
128 facets,
129 const FEkernel<T, U> auto& fn, std::span<const T> constants,
130 md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
131 md::dynamic_extent>>
132 coeffs,
133 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms,
134 std::span<std::type_identity_t<U>> cdofs_b)
135{
136 T value(0);
137 if (facets.empty())
138 return value;
139
140 // Create data structures used in assembly
141 assert(cdofs_b.size() >= 2 * 3 * x_dofmap.extent(1));
142 auto cdofs0 = cdofs_b.first(3 * x_dofmap.extent(1));
143 auto cdofs1 = cdofs_b.last(3 * x_dofmap.extent(1));
144
145 // Iterate over all facets
146 for (std::size_t f = 0; f < facets.extent(0); ++f)
147 {
148 std::array cells = {facets(f, 0, 0), facets(f, 1, 0)};
149 std::array local_facet = {facets(f, 0, 1), facets(f, 1, 1)};
150
151 // Get cell geometry
152 auto x_dofs0 = md::submdspan(x_dofmap, cells[0], md::full_extent);
153 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
154 std::copy_n(&x(x_dofs0[i], 0), 3, std::next(cdofs0.begin(), 3 * i));
155 auto x_dofs1 = md::submdspan(x_dofmap, cells[1], md::full_extent);
156 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
157 std::copy_n(&x(x_dofs1[i], 0), 3, std::next(cdofs1.begin(), 3 * i));
158
159 std::array perm = perms.empty()
160 ? std::array<std::uint8_t, 2>{0, 0}
161 : std::array{perms(cells[0], local_facet[0]),
162 perms(cells[1], local_facet[1])};
163 fn(&value, &coeffs(f, 0, 0), constants.data(), cdofs_b.data(),
164 local_facet.data(), perm.data(), nullptr);
165 }
166
167 return value;
168}
169
171template <dolfinx::scalar T, std::floating_point U>
172T assemble_scalar(
173 const fem::Form<T, U>& M, mdspan2_t x_dofmap,
174 md::mdspan<const U, md::extents<std::size_t, md::dynamic_extent, 3>> x,
175 std::span<const T> constants,
176 const std::map<std::pair<IntegralType, int>,
177 std::pair<std::span<const T>, int>>& coefficients,
178 std::size_t cell_type_idx)
179{
180 std::shared_ptr<const mesh::Mesh<U>> mesh = M.mesh();
181 assert(mesh);
182
183 std::vector<U> cdofs_b(2 * 3 * x_dofmap.extent(1));
184
185 T value = 0;
186 for (int i = 0; i < M.num_integrals(IntegralType::cell, cell_type_idx); ++i)
187 {
188 auto fn = M.kernel(IntegralType::cell, i, cell_type_idx);
189 assert(fn);
190 auto& [coeffs, cstride] = coefficients.at({IntegralType::cell, i});
191 std::span<const std::int32_t> cells
192 = M.domain(IntegralType::cell, i, cell_type_idx);
193 assert(cells.size() * cstride == coeffs.size());
194 value += impl::assemble_cells(
195 x_dofmap, x, cells, fn, constants,
196 md::mdspan(coeffs.data(), cells.size(), cstride), cdofs_b);
197 }
198
199 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> facet_perms;
200 if (M.needs_facet_permutations())
201 {
202 mesh::CellType cell_type = mesh->topology()->cell_types()[cell_type_idx];
203 int num_facets_per_cell
204 = mesh::cell_num_entities(cell_type, mesh->topology()->dim() - 1);
205
206 mesh->topology_mutable()->create_entity_permutations();
207 const std::vector<std::uint8_t>& p
208 = mesh->topology()->get_facet_permutations();
209 facet_perms = md::mdspan(p.data(), p.size() / num_facets_per_cell,
210 num_facets_per_cell);
211 }
212
213 for (int i = 0;
214 i < M.num_integrals(IntegralType::interior_facet, cell_type_idx); ++i)
215 {
216 auto fn = M.kernel(IntegralType::interior_facet, i, cell_type_idx);
217 assert(fn);
218 auto& [coeffs, cstride]
219 = coefficients.at({IntegralType::interior_facet, i});
220 std::span facets = M.domain(IntegralType::interior_facet, i, cell_type_idx);
221
222 constexpr std::size_t num_adjacent_cells = 2;
223 // Two values per each adj. cell (cell index and local facet index).
224 constexpr std::size_t shape1 = 2 * num_adjacent_cells;
225
226 assert((facets.size() / shape1) * 2 * cstride == coeffs.size());
227 value += impl::assemble_interior_facets(
228 x_dofmap, x,
229 md::mdspan<const std::int32_t,
230 md::extents<std::size_t, md::dynamic_extent, 2, 2>>(
231 facets.data(), facets.size() / shape1, 2, 2),
232 fn, constants,
233 md::mdspan<const T, md::extents<std::size_t, md::dynamic_extent, 2,
234 md::dynamic_extent>>(
235 coeffs.data(), facets.size() / shape1, 2, cstride),
236 facet_perms, cdofs_b);
237 }
238
239 for (auto itg_type : {fem::IntegralType::exterior_facet,
241 {
242 md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms
244 ? facet_perms
245 : md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>>{};
246
247 for (int i = 0; i < M.num_integrals(itg_type, cell_type_idx); ++i)
248 {
249 auto fn = M.kernel(itg_type, i, cell_type_idx);
250 assert(fn);
251 auto& [coeffs, cstride] = coefficients.at({itg_type, i});
252
253 std::span entities = M.domain(itg_type, i, cell_type_idx);
254
255 // Two values per each adj. cell (cell index and local entity index).
256 assert((entities.size() / 2) * cstride == coeffs.size());
257 value += impl::assemble_entities(
258 x_dofmap, x,
259 md::mdspan<const std::int32_t,
260 md::extents<std::size_t, md::dynamic_extent, 2>>(
261 entities.data(), entities.size() / 2, 2),
262 fn, constants,
263 md::mdspan(coeffs.data(), entities.size() / 2, cstride), perms,
264 cdofs_b);
265 }
266 }
267
268 return value;
269}
270
271} // namespace dolfinx::fem::impl
Functions supporting finite element method operations.
void cells(la::SparsityPattern &pattern, const std::pair< R0, R1 > &cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.h:37
@ vertex
Vertex.
Definition Form.h:45
@ interior_facet
Interior facet.
Definition Form.h:44
@ ridge
Ridge.
Definition Form.h:46
@ cell
Cell.
Definition Form.h:42
@ exterior_facet
Exterior facet.
Definition Form.h:43
CellType
Cell type identifier.
Definition cell_types.h:22
int cell_num_entities(CellType type, int dim)
Number of entities of dimension.
Definition cell_types.cpp:92