Skip to content

Commit c274e17

Browse files
committed
support DoF coupling in FESystem
1 parent 2702e05 commit c274e17

File tree

4 files changed

+167
-1
lines changed

4 files changed

+167
-1
lines changed

Diff for: source/fe/fe_system.cc

+63
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,69 @@ FESystem<dim, spacedim>::initialize(
20092009
Assert(index == this->n_dofs_per_line(), ExcInternalError());
20102010
});
20112011

2012+
2013+
// Compute local_dof_sparsity_pattern if any of our base elements contains a
2014+
// non-empty one (empty denotes the default of all DoFs coupling within a
2015+
// cell). Note the we currently only handle coupling within a base element and
2016+
// not between two different base elements. Handling the latter could be
2017+
// doable if the underlying element happens to be identical, but we currently
2018+
// have no functionality to compute the coupling between different elements
2019+
// with a pattern (for example FE_Q_iso_Q1 with different degrees).
2020+
{
2021+
// Does any of our base elements not couple all DoFs?
2022+
const bool have_nonempty = [&]() -> bool {
2023+
for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2024+
{
2025+
if (!this->base_element(b).get_local_dof_sparsity_pattern().empty() &&
2026+
(this->element_multiplicity(b) > 0))
2027+
return true;
2028+
}
2029+
return false;
2030+
}();
2031+
2032+
if (have_nonempty)
2033+
{
2034+
this->local_dof_sparsity_pattern.reinit(this->n_dofs_per_cell(),
2035+
this->n_dofs_per_cell());
2036+
// by default, everything couples:
2037+
this->local_dof_sparsity_pattern.fill(true);
2038+
2039+
unsigned int current_dof_index = 0;
2040+
2041+
for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2042+
{
2043+
const auto &pattern =
2044+
this->base_element(b).get_local_dof_sparsity_pattern();
2045+
const unsigned int m = this->element_multiplicity(b);
2046+
2047+
if (!pattern.empty())
2048+
{
2049+
// the base element b with multiplicity m has a sparsity pattern
2050+
// where not all DoFs couple. Within this base element, each of
2051+
// them couples to each other one only based on this pattern.
2052+
// This means we can copy m times m copies of the pattern into
2053+
// ours:
2054+
const unsigned int n_dofs = pattern.size(0);
2055+
for (unsigned int bi = 0; bi < m; ++bi)
2056+
for (unsigned int bj = 0; bj < m; ++bj)
2057+
for (unsigned int i = 0; i < n_dofs; ++i)
2058+
for (unsigned int j = 0; j < n_dofs; ++j)
2059+
this->local_dof_sparsity_pattern(
2060+
current_dof_index + bi * n_dofs + i,
2061+
current_dof_index + bj * n_dofs + j) = pattern(i, j);
2062+
}
2063+
2064+
current_dof_index += this->base_element(b).n_dofs_per_cell() * m;
2065+
}
2066+
}
2067+
else
2068+
{
2069+
// None of our base elements has a sparsity pattern set, meaning we
2070+
// don't have to do anything (the default empty
2071+
// local_dof_sparsity_pattern is correct).
2072+
}
2073+
}
2074+
20122075
// wait for all of this to finish
20132076
init_tasks.join_all();
20142077
}

Diff for: tests/fe/local_sparsity_01.cc

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// ------------------------------------------------------------------------
2+
//
3+
// SPDX-License-Identifier: LGPL-2.1-or-later
4+
// Copyright (C) 2024 - 2025 by the deal.II authors
5+
//
6+
// This file is part of the deal.II library.
7+
//
8+
// Part of the source code is dual licensed under Apache-2.0 WITH
9+
// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10+
// governing the source code and code contributions can be found in
11+
// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12+
//
13+
// ------------------------------------------------------------------------
14+
15+
// Check FiniteElement::get_local_dof_sparsity_pattern() for FESystem.
16+
17+
#include <deal.II/dofs/dof_handler.h>
18+
#include <deal.II/dofs/dof_tools.h>
19+
20+
#include "deal.II/fe/fe_system.h"
21+
#include <deal.II/fe/fe_dgq.h>
22+
#include <deal.II/fe/fe_q.h>
23+
#include <deal.II/fe/fe_q_iso_q1.h>
24+
#include <deal.II/fe/mapping_q1.h>
25+
26+
#include <deal.II/grid/grid_generator.h>
27+
#include <deal.II/grid/tria.h>
28+
29+
#include <deal.II/lac/dynamic_sparsity_pattern.h>
30+
#include <deal.II/lac/sparsity_pattern.h>
31+
32+
#include "../tests.h"
33+
34+
template <int dim>
35+
void
36+
test(const FiniteElement<dim> &fe, const unsigned int n_subdivisions = 1)
37+
{
38+
const auto &pattern = fe.get_local_dof_sparsity_pattern();
39+
deallog << fe.get_name() << ":\n";
40+
41+
if (!pattern.empty())
42+
{
43+
for (unsigned int i = 0; i < pattern.size(0); ++i)
44+
{
45+
for (unsigned int j = 0; j < pattern.size(1); ++j)
46+
deallog << (pattern(i, j) == true ? "X" : ".");
47+
deallog << "\n";
48+
}
49+
deallog << std::endl;
50+
}
51+
}
52+
53+
int
54+
main()
55+
{
56+
initlog();
57+
58+
// The simplest case is a single iso Q1:
59+
test<1>(FE_Q_iso_Q1<1>(2), 1);
60+
// The 2 iso Q1 elements couple using their pattern:
61+
test<1>(FESystem<1, 1>(FE_DGQ<1>(1), 1, FE_Q_iso_Q1<1>(2), 2), 1);
62+
// The coupling between the first two to the third copy is a full coupling
63+
// currently, because we don't detect this yet:
64+
test<1>(FESystem<1, 1>(FE_Q_iso_Q1<1>(2), 2, FE_Q_iso_Q1<1>(2), 1), 1);
65+
// Different iso_Q1 degrees always couple fully (off diagonal blocks):
66+
test<1>(FESystem<1, 1>(FE_Q_iso_Q1<1>(2), 1, FE_Q_iso_Q1<1>(3), 1), 1);
67+
}

Diff for: tests/fe/local_sparsity_01.output

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
DEAL::FE_Q_iso_Q1<1>(2):
3+
X.X
4+
.XX
5+
XXX
6+
7+
DEAL::FESystem<1>[FE_DGQ<1>(1)-FE_Q_iso_Q1<1>(2)^2]:
8+
XXXXXXXX
9+
XXXXXXXX
10+
XXX.XX.X
11+
XX.XX.XX
12+
XXXXXXXX
13+
XXX.XX.X
14+
XX.XX.XX
15+
XXXXXXXX
16+
17+
DEAL::FESystem<1>[FE_Q_iso_Q1<1>(2)^2-FE_Q_iso_Q1<1>(2)]:
18+
X.XX.XXXX
19+
.XX.XXXXX
20+
XXXXXXXXX
21+
X.XX.XXXX
22+
.XX.XXXXX
23+
XXXXXXXXX
24+
XXXXXXX.X
25+
XXXXXX.XX
26+
XXXXXXXXX
27+
28+
DEAL::FESystem<1>[FE_Q_iso_Q1<1>(2)-FE_Q_iso_Q1<1>(3)]:
29+
X.XXXXX
30+
.XXXXXX
31+
XXXXXXX
32+
XXXX.X.
33+
XXX.X.X
34+
XXXX.XX
35+
XXX.XXX
36+

Diff for: tests/fe/local_sparsity_q_iso_q1.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//
1313
// ------------------------------------------------------------------------
1414

15-
// Assemble the sparsity pattern for a Q1 finite element space and a an iso Q
15+
// Assemble the sparsity pattern for a Q1 finite element space and an iso Q
1616
// element space with the same number of subdivisions, and check we get the same
1717
// sparsity patterns.
1818

0 commit comments

Comments
 (0)