Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/d7/d95/assemble__matrix__impl_8h_source.html
DOLFINx 0.6.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
assemble_matrix_impl.h
1// Copyright (C) 2018-2019 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 "DofMap.h"
10#include "Form.h"
11#include "FunctionSpace.h"
12#include "utils.h"
13#include <algorithm>
14#include <dolfinx/graph/AdjacencyList.h>
15#include <dolfinx/la/utils.h>
16#include <dolfinx/mesh/Geometry.h>
17#include <dolfinx/mesh/Mesh.h>
18#include <dolfinx/mesh/Topology.h>
19#include <functional>
20#include <iterator>
21#include <span>
22#include <vector>
23
24namespace dolfinx::fem::impl
25{
26
28template <typename T>
29void assemble_cells(
30 la::MatSet<T> auto mat_set, const mesh::Geometry& geometry,
31 std::span<const std::int32_t> cells,
32 const std::function<void(const std::span<T>&,
33 const std::span<const std::uint32_t>&,
34 std::int32_t, int)>& dof_transform,
35 const graph::AdjacencyList<std::int32_t>& dofmap0, int bs0,
36 const std::function<void(const std::span<T>&,
37 const std::span<const std::uint32_t>&,
38 std::int32_t, int)>& dof_transform_to_transpose,
39 const graph::AdjacencyList<std::int32_t>& dofmap1, int bs1,
40 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1,
41 FEkernel<T> auto kernel, std::span<const T> coeffs, int cstride,
42 std::span<const T> constants, std::span<const std::uint32_t> cell_info)
43{
44 if (cells.empty())
45 return;
46
47 // Prepare cell geometry
48 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
49 const std::size_t num_dofs_g = geometry.cmap().dim();
50 std::span<const double> x = geometry.x();
51
52 // Iterate over active cells
53 const int num_dofs0 = dofmap0.links(0).size();
54 const int num_dofs1 = dofmap1.links(0).size();
55 const int ndim0 = bs0 * num_dofs0;
56 const int ndim1 = bs1 * num_dofs1;
57 std::vector<T> Ae(ndim0 * ndim1);
58 std::span<T> _Ae(Ae);
59 std::vector<scalar_value_type_t<T>> coordinate_dofs(3 * num_dofs_g);
60
61 // Iterate over active cells
62 for (std::size_t index = 0; index < cells.size(); ++index)
63 {
64 std::int32_t c = cells[index];
65
66 // Get cell coordinates/geometry
67 auto x_dofs = x_dofmap.links(c);
68 for (std::size_t i = 0; i < x_dofs.size(); ++i)
69 {
70 std::copy_n(std::next(x.begin(), 3 * x_dofs[i]), 3,
71 std::next(coordinate_dofs.begin(), 3 * i));
72 }
73
74 // Tabulate tensor
75 std::fill(Ae.begin(), Ae.end(), 0);
76 kernel(Ae.data(), coeffs.data() + index * cstride, constants.data(),
77 coordinate_dofs.data(), nullptr, nullptr);
78
79 dof_transform(_Ae, cell_info, c, ndim1);
80 dof_transform_to_transpose(_Ae, cell_info, c, ndim0);
81
82 // Zero rows/columns for essential bcs
83 auto dofs0 = dofmap0.links(c);
84 auto dofs1 = dofmap1.links(c);
85 if (!bc0.empty())
86 {
87 for (int i = 0; i < num_dofs0; ++i)
88 {
89 for (int k = 0; k < bs0; ++k)
90 {
91 if (bc0[bs0 * dofs0[i] + k])
92 {
93 // Zero row bs0 * i + k
94 const int row = bs0 * i + k;
95 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0.0);
96 }
97 }
98 }
99 }
100
101 if (!bc1.empty())
102 {
103 for (int j = 0; j < num_dofs1; ++j)
104 {
105 for (int k = 0; k < bs1; ++k)
106 {
107 if (bc1[bs1 * dofs1[j] + k])
108 {
109 // Zero column bs1 * j + k
110 const int col = bs1 * j + k;
111 for (int row = 0; row < ndim0; ++row)
112 Ae[row * ndim1 + col] = 0.0;
113 }
114 }
115 }
116 }
117
118 mat_set(dofs0, dofs1, Ae);
119 }
120}
121
123template <typename T>
124void assemble_exterior_facets(
125 la::MatSet<T> auto mat_set, const mesh::Geometry& geometry,
126 std::span<const std::int32_t> facets,
127 const std::function<void(const std::span<T>&,
128 const std::span<const std::uint32_t>&,
129 std::int32_t, int)>& dof_transform,
130 const graph::AdjacencyList<std::int32_t>& dofmap0, int bs0,
131 const std::function<void(const std::span<T>&,
132 const std::span<const std::uint32_t>&,
133 std::int32_t, int)>& dof_transform_to_transpose,
134 const graph::AdjacencyList<std::int32_t>& dofmap1, int bs1,
135 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1,
136 FEkernel<T> auto kernel, std::span<const T> coeffs, int cstride,
137 std::span<const T> constants, std::span<const std::uint32_t> cell_info)
138{
139 if (facets.empty())
140 return;
141
142 // Prepare cell geometry
143 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
144 const std::size_t num_dofs_g = geometry.cmap().dim();
145 std::span<const double> x = geometry.x();
146
147 // Data structures used in assembly
148 std::vector<scalar_value_type_t<T>> coordinate_dofs(3 * num_dofs_g);
149 const int num_dofs0 = dofmap0.links(0).size();
150 const int num_dofs1 = dofmap1.links(0).size();
151 const int ndim0 = bs0 * num_dofs0;
152 const int ndim1 = bs1 * num_dofs1;
153 std::vector<T> Ae(ndim0 * ndim1);
154 std::span<T> _Ae(Ae);
155 assert(facets.size() % 2 == 0);
156 for (std::size_t index = 0; index < facets.size(); index += 2)
157 {
158 std::int32_t cell = facets[index];
159 std::int32_t local_facet = facets[index + 1];
160
161 // Get cell coordinates/geometry
162 auto x_dofs = x_dofmap.links(cell);
163 for (std::size_t i = 0; i < x_dofs.size(); ++i)
164 {
165 std::copy_n(std::next(x.begin(), 3 * x_dofs[i]), 3,
166 std::next(coordinate_dofs.begin(), 3 * i));
167 }
168
169 // Tabulate tensor
170 std::fill(Ae.begin(), Ae.end(), 0);
171 kernel(Ae.data(), coeffs.data() + index / 2 * cstride, constants.data(),
172 coordinate_dofs.data(), &local_facet, nullptr);
173
174 dof_transform(_Ae, cell_info, cell, ndim1);
175 dof_transform_to_transpose(_Ae, cell_info, cell, ndim0);
176
177 // Zero rows/columns for essential bcs
178 auto dofs0 = dofmap0.links(cell);
179 auto dofs1 = dofmap1.links(cell);
180 if (!bc0.empty())
181 {
182 for (int i = 0; i < num_dofs0; ++i)
183 {
184 for (int k = 0; k < bs0; ++k)
185 {
186 if (bc0[bs0 * dofs0[i] + k])
187 {
188 // Zero row bs0 * i + k
189 const int row = bs0 * i + k;
190 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0.0);
191 }
192 }
193 }
194 }
195 if (!bc1.empty())
196 {
197 for (int j = 0; j < num_dofs1; ++j)
198 {
199 for (int k = 0; k < bs1; ++k)
200 {
201 if (bc1[bs1 * dofs1[j] + k])
202 {
203 // Zero column bs1 * j + k
204 const int col = bs1 * j + k;
205 for (int row = 0; row < ndim0; ++row)
206 Ae[row * ndim1 + col] = 0.0;
207 }
208 }
209 }
210 }
211
212 mat_set(dofs0, dofs1, Ae);
213 }
214}
215
217template <typename T>
218void assemble_interior_facets(
219 la::MatSet<T> auto mat_set, const mesh::Geometry& geometry,
220 int num_cell_facets, std::span<const std::int32_t> facets,
221 const std::function<void(const std::span<T>&,
222 const std::span<const std::uint32_t>&,
223 std::int32_t, int)>& dof_transform,
224 const DofMap& dofmap0, int bs0,
225 const std::function<void(const std::span<T>&,
226 const std::span<const std::uint32_t>&,
227 std::int32_t, int)>& dof_transform_to_transpose,
228 const DofMap& dofmap1, int bs1, std::span<const std::int8_t> bc0,
229 std::span<const std::int8_t> bc1, FEkernel<T> auto kernel,
230 std::span<const T> coeffs, int cstride, std::span<const int> offsets,
231 std::span<const T> constants, std::span<const std::uint32_t> cell_info,
232 const std::function<std::uint8_t(std::size_t)>& get_perm)
233{
234 if (facets.empty())
235 return;
236
237 // Prepare cell geometry
238 const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
239 const std::size_t num_dofs_g = geometry.cmap().dim();
240 std::span<const double> x = geometry.x();
241
242 // Data structures used in assembly
243 using X = scalar_value_type_t<T>;
244 std::vector<X> coordinate_dofs(2 * num_dofs_g * 3);
245 std::span<X> cdofs0(coordinate_dofs.data(), num_dofs_g * 3);
246 std::span<X> cdofs1(coordinate_dofs.data() + num_dofs_g * 3, num_dofs_g * 3);
247
248 std::vector<T> Ae, be;
249 std::vector<T> coeff_array(2 * offsets.back());
250 assert(offsets.back() == cstride);
251
252 // Temporaries for joint dofmaps
253 std::vector<std::int32_t> dmapjoint0, dmapjoint1;
254 assert(facets.size() % 4 == 0);
255 for (std::size_t index = 0; index < facets.size(); index += 4)
256 {
257 std::array<std::int32_t, 2> cells = {facets[index], facets[index + 2]};
258 std::array<std::int32_t, 2> local_facet
259 = {facets[index + 1], facets[index + 3]};
260
261 // Get cell geometry
262 auto x_dofs0 = x_dofmap.links(cells[0]);
263 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
264 {
265 std::copy_n(std::next(x.begin(), 3 * x_dofs0[i]), 3,
266 std::next(cdofs0.begin(), 3 * i));
267 }
268 auto x_dofs1 = x_dofmap.links(cells[1]);
269 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
270 {
271 std::copy_n(std::next(x.begin(), 3 * x_dofs1[i]), 3,
272 std::next(cdofs1.begin(), 3 * i));
273 }
274
275 // Get dof maps for cells and pack
276 std::span<const std::int32_t> dmap0_cell0 = dofmap0.cell_dofs(cells[0]);
277 std::span<const std::int32_t> dmap0_cell1 = dofmap0.cell_dofs(cells[1]);
278 dmapjoint0.resize(dmap0_cell0.size() + dmap0_cell1.size());
279 std::copy(dmap0_cell0.begin(), dmap0_cell0.end(), dmapjoint0.begin());
280 std::copy(dmap0_cell1.begin(), dmap0_cell1.end(),
281 std::next(dmapjoint0.begin(), dmap0_cell0.size()));
282
283 std::span<const std::int32_t> dmap1_cell0 = dofmap1.cell_dofs(cells[0]);
284 std::span<const std::int32_t> dmap1_cell1 = dofmap1.cell_dofs(cells[1]);
285 dmapjoint1.resize(dmap1_cell0.size() + dmap1_cell1.size());
286 std::copy(dmap1_cell0.begin(), dmap1_cell0.end(), dmapjoint1.begin());
287 std::copy(dmap1_cell1.begin(), dmap1_cell1.end(),
288 std::next(dmapjoint1.begin(), dmap1_cell0.size()));
289
290 const int num_rows = bs0 * dmapjoint0.size();
291 const int num_cols = bs1 * dmapjoint1.size();
292
293 // Tabulate tensor
294 Ae.resize(num_rows * num_cols);
295 std::fill(Ae.begin(), Ae.end(), 0);
296
297 const std::array perm{
298 get_perm(cells[0] * num_cell_facets + local_facet[0]),
299 get_perm(cells[1] * num_cell_facets + local_facet[1])};
300 kernel(Ae.data(), coeffs.data() + index / 2 * cstride, constants.data(),
301 coordinate_dofs.data(), local_facet.data(), perm.data());
302
303 std::span<T> _Ae(Ae);
304 std::span<T> sub_Ae0 = _Ae.subspan(bs0 * dmap0_cell0.size() * num_cols,
305 bs0 * dmap0_cell1.size() * num_cols);
306 std::span<T> sub_Ae1
307 = _Ae.subspan(bs1 * dmap1_cell0.size(),
308 num_rows * num_cols - bs1 * dmap1_cell0.size());
309
310 // Need to apply DOF transformations for parts of the matrix due to cell 0
311 // and cell 1. For example, if the space has 3 DOFs, then Ae will be 6 by 6
312 // (3 rows/columns for each cell). Subspans are used to offset to the right
313 // blocks of the matrix
314
315 dof_transform(_Ae, cell_info, cells[0], num_cols);
316 dof_transform(sub_Ae0, cell_info, cells[1], num_cols);
317 dof_transform_to_transpose(_Ae, cell_info, cells[0], num_rows);
318 dof_transform_to_transpose(sub_Ae1, cell_info, cells[1], num_rows);
319
320 // Zero rows/columns for essential bcs
321 if (!bc0.empty())
322 {
323 for (std::size_t i = 0; i < dmapjoint0.size(); ++i)
324 {
325 for (int k = 0; k < bs0; ++k)
326 {
327 if (bc0[bs0 * dmapjoint0[i] + k])
328 {
329 // Zero row bs0 * i + k
330 std::fill_n(std::next(Ae.begin(), num_cols * (bs0 * i + k)),
331 num_cols, 0.0);
332 }
333 }
334 }
335 }
336 if (!bc1.empty())
337 {
338 for (std::size_t j = 0; j < dmapjoint1.size(); ++j)
339 {
340 for (int k = 0; k < bs1; ++k)
341 {
342 if (bc1[bs1 * dmapjoint1[j] + k])
343 {
344 // Zero column bs1 * j + k
345 for (int m = 0; m < num_rows; ++m)
346 Ae[m * num_cols + bs1 * j + k] = 0.0;
347 }
348 }
349 }
350 }
351
352 mat_set(dmapjoint0, dmapjoint1, Ae);
353 }
354}
355
361template <typename T>
362void assemble_matrix(
363 la::MatSet<T> auto mat_set, const Form<T>& a, std::span<const T> constants,
364 const std::map<std::pair<IntegralType, int>,
365 std::pair<std::span<const T>, int>>& coefficients,
366 std::span<const std::int8_t> bc0, std::span<const std::int8_t> bc1)
367{
368 std::shared_ptr<const mesh::Mesh> mesh = a.mesh();
369 assert(mesh);
370
371 // Get dofmap data
372 std::shared_ptr<const fem::DofMap> dofmap0
373 = a.function_spaces().at(0)->dofmap();
374 std::shared_ptr<const fem::DofMap> dofmap1
375 = a.function_spaces().at(1)->dofmap();
376 assert(dofmap0);
377 assert(dofmap1);
378 const graph::AdjacencyList<std::int32_t>& dofs0 = dofmap0->list();
379 const int bs0 = dofmap0->bs();
380 const graph::AdjacencyList<std::int32_t>& dofs1 = dofmap1->list();
381 const int bs1 = dofmap1->bs();
382
383 std::shared_ptr<const fem::FiniteElement> element0
384 = a.function_spaces().at(0)->element();
385 std::shared_ptr<const fem::FiniteElement> element1
386 = a.function_spaces().at(1)->element();
387 const std::function<void(const std::span<T>&,
388 const std::span<const std::uint32_t>&, std::int32_t,
389 int)>& dof_transform
390 = element0->get_dof_transformation_function<T>();
391 const std::function<void(const std::span<T>&,
392 const std::span<const std::uint32_t>&, std::int32_t,
393 int)>& dof_transform_to_transpose
394 = element1->get_dof_transformation_to_transpose_function<T>();
395
396 const bool needs_transformation_data
397 = element0->needs_dof_transformations()
398 or element1->needs_dof_transformations()
400 std::span<const std::uint32_t> cell_info;
401 if (needs_transformation_data)
402 {
403 mesh->topology_mutable().create_entity_permutations();
404 cell_info = std::span(mesh->topology().get_cell_permutation_info());
405 }
406
407 for (int i : a.integral_ids(IntegralType::cell))
408 {
409 const auto& fn = a.kernel(IntegralType::cell, i);
410 const auto& [coeffs, cstride] = coefficients.at({IntegralType::cell, i});
411 const std::vector<std::int32_t>& cells = a.cell_domains(i);
412 impl::assemble_cells(mat_set, mesh->geometry(), cells, dof_transform, dofs0,
413 bs0, dof_transform_to_transpose, dofs1, bs1, bc0, bc1,
414 fn, coeffs, cstride, constants, cell_info);
415 }
416
418 {
419 const auto& fn = a.kernel(IntegralType::exterior_facet, i);
420 const auto& [coeffs, cstride]
421 = coefficients.at({IntegralType::exterior_facet, i});
422 const std::vector<std::int32_t>& facets = a.exterior_facet_domains(i);
423 impl::assemble_exterior_facets(
424 mat_set, mesh->geometry(), facets, dof_transform, dofs0, bs0,
425 dof_transform_to_transpose, dofs1, bs1, bc0, bc1, fn, coeffs, cstride,
426 constants, cell_info);
427 }
428
430 {
431 std::function<std::uint8_t(std::size_t)> get_perm;
433 {
434 mesh->topology_mutable().create_entity_permutations();
435 const std::vector<std::uint8_t>& perms
436 = mesh->topology().get_facet_permutations();
437 get_perm = [&perms](std::size_t i) { return perms[i]; };
438 }
439 else
440 get_perm = [](std::size_t) { return 0; };
441
442 int num_cell_facets = mesh::cell_num_entities(mesh->topology().cell_type(),
443 mesh->topology().dim() - 1);
444 const std::vector<int> c_offsets = a.coefficient_offsets();
446 {
447 const auto& fn = a.kernel(IntegralType::interior_facet, i);
448 const auto& [coeffs, cstride]
449 = coefficients.at({IntegralType::interior_facet, i});
450 const std::vector<std::int32_t>& facets = a.interior_facet_domains(i);
451 impl::assemble_interior_facets(
452 mat_set, mesh->geometry(), num_cell_facets, facets, dof_transform,
453 *dofmap0, bs0, dof_transform_to_transpose, *dofmap1, bs1, bc0, bc1,
454 fn, coeffs, cstride, c_offsets, constants, cell_info, get_perm);
455 }
456 }
457}
458
459} // namespace dolfinx::fem::impl
Degree-of-freedom map representations and tools.
int dim() const
The dimension of the geometry element space.
Definition: CoordinateElement.cpp:183
Degree-of-freedom map.
Definition: DofMap.h:72
A representation of finite element variational forms.
Definition: Form.h:64
bool needs_facet_permutations() const
Get bool indicating whether permutation data needs to be passed into these integrals.
Definition: Form.h:326
const std::vector< std::int32_t > & cell_domains(int i) const
Get the list of cell indices for the ith integral (kernel) for the cell domain type.
Definition: Form.h:281
const std::vector< std::int32_t > & exterior_facet_domains(int i) const
List of (cell_index, local_facet_index) pairs for the ith integral (kernel) for the exterior facet do...
Definition: Form.h:294
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell. Used to pack data for multiple coefficients in...
Definition: Form.h:331
const std::function< void(T *, const T *, const T *, const scalar_value_type_t *, const int *, const std::uint8_t *)> & kernel(IntegralType type, int i) const
Get the function for 'kernel' for integral i of given type.
Definition: Form.h:194
const std::vector< std::shared_ptr< const FunctionSpace > > & function_spaces() const
Return function spaces for all arguments.
Definition: Form.h:182
std::vector< int > integral_ids(IntegralType type) const
Get the IDs for integrals (kernels) for given integral type. The IDs correspond to the domain IDs whi...
Definition: Form.h:249
std::shared_ptr< const mesh::Mesh > mesh() const
Extract common mesh for the form.
Definition: Form.h:177
const std::vector< std::int32_t > & interior_facet_domains(int i) const
Get the list of (cell_index_0, local_facet_index_0, cell_index_1, local_facet_index_1) quadruplets fo...
Definition: Form.h:309
int num_integrals(IntegralType type) const
Number of integrals of given type.
Definition: Form.h:228
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition: AdjacencyList.h:27
std::span< T > links(int node)
Get the links (edges) for given node.
Definition: AdjacencyList.h:109
Geometry stores the geometry imposed on a mesh.
Definition: Geometry.h:29
const graph::AdjacencyList< std::int32_t > & dofmap() const
DOF map.
Definition: Geometry.cpp:21
std::span< const double > x() const
Access geometry degrees-of-freedom data (const version).
Definition: Geometry.cpp:33
const fem::CoordinateElement & cmap() const
The element that describes the geometry map.
Definition: Geometry.cpp:35
Finite element cell kernel concept.
Definition: utils.h:82
Matrix accumulate/set concept for functions that can be used in assemblers to accumulate or set value...
Definition: utils.h:28
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
int cell_num_entities(CellType type, int dim)
Number of entities of dimension dim.
Definition: cell_types.cpp:139