deal.II version GIT relicensing-6917-gb466a1809f 2026-10-16 06:30:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
mg_transfer_prebuilt.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2003 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
16
19
20#include <deal.II/fe/fe.h>
21
22#include <deal.II/grid/tria.h>
24
35#include <deal.II/lac/vector.h>
36
39
40#include <algorithm>
41
43
44
45template <typename VectorType>
47 const MGConstrainedDoFs &mg_c)
48{
49 this->mg_constrained_dofs = &mg_c;
50}
51
52
53
54template <typename VectorType>
55void
57 const MGConstrainedDoFs &mg_c)
58{
59 this->mg_constrained_dofs = &mg_c;
60}
61
62
63
64template <typename VectorType>
65void
67{
69 prolongation_matrices.resize(0);
70 prolongation_sparsities.resize(0);
71 interface_dofs.resize(0);
72}
73
74
75
76template <typename VectorType>
77void
79 VectorType &dst,
80 const VectorType &src) const
81{
82 Assert((to_level >= 1) && (to_level <= prolongation_matrices.size()),
83 ExcIndexRange(to_level, 1, prolongation_matrices.size() + 1));
84
85 if (this->mg_constrained_dofs != nullptr &&
86 this->mg_constrained_dofs->get_user_constraint_matrix(to_level - 1)
87 .get_local_lines()
88 .size() > 0)
89 {
90 VectorType copy_src(src);
91 this->mg_constrained_dofs->get_user_constraint_matrix(to_level - 1)
92 .distribute(copy_src);
93 prolongation_matrices[to_level - 1]->vmult(dst, copy_src);
94 }
95 else
96 {
97 prolongation_matrices[to_level - 1]->vmult(dst, src);
98 }
99}
100
101
102
103template <typename VectorType>
104void
106 VectorType &dst,
107 const VectorType &src) const
108{
109 Assert((from_level >= 1) && (from_level <= prolongation_matrices.size()),
110 ExcIndexRange(from_level, 1, prolongation_matrices.size() + 1));
111
112 prolongation_matrices[from_level - 1]->Tvmult_add(dst, src);
113}
114
115
116namespace
117{
122 void
123 replace(const MGConstrainedDoFs *mg_constrained_dofs,
124 const unsigned int level,
125 std::vector<types::global_dof_index> &dof_indices)
126 {
127 if (mg_constrained_dofs != nullptr &&
128 mg_constrained_dofs->get_level_constraints(level).n_constraints() > 0)
129 for (auto &ind : dof_indices)
130 if (mg_constrained_dofs->get_level_constraints(level)
131 .is_identity_constrained(ind))
132 {
133 Assert(mg_constrained_dofs->get_level_constraints(level)
135 ->size() == 1,
137 ind = mg_constrained_dofs->get_level_constraints(level)
139 ->front()
140 .first;
141 }
142 }
143} // namespace
144
145template <typename VectorType>
146template <int dim, int spacedim>
147void
149 const DoFHandler<dim, spacedim> &dof_handler)
150{
151 Assert(dof_handler.has_level_dofs(),
153 "The underlying DoFHandler object has not had its "
154 "distribute_mg_dofs() function called, but this is a prerequisite "
155 "for multigrid transfers. You will need to call this function, "
156 "probably close to where you already call distribute_dofs()."));
157
158 const unsigned int n_levels =
159 dof_handler.get_triangulation().n_global_levels();
160 const unsigned int dofs_per_cell = dof_handler.get_fe().n_dofs_per_cell();
161
162 this->sizes.resize(n_levels);
163 for (unsigned int l = 0; l < n_levels; ++l)
164 this->sizes[l] = dof_handler.n_dofs(l);
165
166 // reset the size of the array of
167 // matrices. call resize(0) first,
168 // in order to delete all elements
169 // and clear their memory. then
170 // repopulate these arrays
171 //
172 // note that on resize(0), the
173 // shared_ptr class takes care of
174 // deleting the object it points to
175 // by itself
176 prolongation_matrices.resize(0);
177 prolongation_sparsities.resize(0);
178 prolongation_matrices.reserve(n_levels - 1);
179 prolongation_sparsities.reserve(n_levels - 1);
180
181 for (unsigned int i = 0; i < n_levels - 1; ++i)
182 {
183 prolongation_sparsities.emplace_back(
185 prolongation_matrices.emplace_back(
187 }
188
189 // two fields which will store the
190 // indices of the multigrid dofs
191 // for a cell and one of its children
192 std::vector<types::global_dof_index> dof_indices_parent(dofs_per_cell);
193 std::vector<types::global_dof_index> dof_indices_child(dofs_per_cell);
194 std::vector<types::global_dof_index> entries(dofs_per_cell);
195
196 // for each level: first build the sparsity
197 // pattern of the matrices and then build the
198 // matrices themselves. note that we only
199 // need to take care of cells on the coarser
200 // level which have children
201 for (unsigned int level = 0; level < n_levels - 1; ++level)
202 {
203 // reset the dimension of the structure. note that for the number of
204 // entries per row, the number of parent dofs coupling to a child dof is
205 // necessary. this, of course, is the number of degrees of freedom per
206 // cell
207 //
208 // increment dofs_per_cell since a useless diagonal element will be
209 // stored
210 const IndexSet level_p1_relevant_dofs =
212 DynamicSparsityPattern dsp(this->sizes[level + 1],
213 this->sizes[level],
214 level_p1_relevant_dofs);
215 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
216 if (cell->has_children() && cell->is_locally_owned_on_level())
217 {
218 cell->get_mg_dof_indices(dof_indices_parent);
219
220 replace(this->mg_constrained_dofs, level, dof_indices_parent);
221
222 Assert(cell->n_children() ==
225 for (unsigned int child = 0; child < cell->n_children(); ++child)
226 {
227 // set an alias to the prolongation matrix for this child
228 const FullMatrix<double> &prolongation =
229 dof_handler.get_fe().get_prolongation_matrix(
230 child, cell->refinement_case());
231
232 Assert(prolongation.n() != 0, ExcNoProlongation());
233
234 cell->child(child)->get_mg_dof_indices(dof_indices_child);
235
236 replace(this->mg_constrained_dofs,
237 level + 1,
238 dof_indices_child);
239
240 // now tag the entries in the
241 // matrix which will be used
242 // for this pair of parent/child
243 for (unsigned int i = 0; i < dofs_per_cell; ++i)
244 {
245 entries.resize(0);
246 for (unsigned int j = 0; j < dofs_per_cell; ++j)
247 if (prolongation(i, j) != 0)
248 entries.push_back(dof_indices_parent[j]);
249 dsp.add_entries(dof_indices_child[i],
250 entries.begin(),
251 entries.end());
252 }
253 }
254 }
255
256#ifdef DEAL_II_WITH_MPI
258 VectorType>::requires_distributed_sparsity_pattern)
259 {
260 // Since PETSc matrices do not offer the functionality to fill up in-
261 // complete sparsity patterns on their own, the sparsity pattern must
262 // be manually distributed.
263
264 // Distribute sparsity pattern
266 dsp,
267 dof_handler.locally_owned_mg_dofs(level + 1),
268 dof_handler.get_mpi_communicator(),
269 dsp.row_index_set());
270 }
271#endif
272
274 *prolongation_matrices[level],
275 *prolongation_sparsities[level],
276 level,
277 dsp,
278 dof_handler);
279 dsp.reinit(0, 0);
280
281 // In the end, the entries in this object will only be real valued.
282 // Nevertheless, we have to take the underlying scalar type of the
283 // vector we want to use this class with. The global matrix the entries
284 // of this matrix are copied into has to be able to perform a
285 // matrix-vector multiplication and this is in general only implemented if
286 // the scalar type for matrix and vector is the same. Furthermore,
287 // copying entries between this local object and the global matrix is only
288 // implemented if the objects have the same scalar type.
290
291 // now actually build the matrices
292 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
293 if (cell->has_children() && cell->is_locally_owned_on_level())
294 {
295 cell->get_mg_dof_indices(dof_indices_parent);
296
297 replace(this->mg_constrained_dofs, level, dof_indices_parent);
298
299 Assert(cell->n_children() ==
302 for (unsigned int child = 0; child < cell->n_children(); ++child)
303 {
304 // set an alias to the prolongation matrix for this child
305 prolongation = dof_handler.get_fe().get_prolongation_matrix(
306 child, cell->refinement_case());
307
308 if (this->mg_constrained_dofs != nullptr &&
309 this->mg_constrained_dofs->have_boundary_indices())
310 for (unsigned int j = 0; j < dofs_per_cell; ++j)
311 if (this->mg_constrained_dofs->is_boundary_index(
312 level, dof_indices_parent[j]))
313 for (unsigned int i = 0; i < dofs_per_cell; ++i)
314 prolongation(i, j) = 0.;
315
316 cell->child(child)->get_mg_dof_indices(dof_indices_child);
317
318 replace(this->mg_constrained_dofs,
319 level + 1,
320 dof_indices_child);
321
322 // now set the entries in the matrix
323 for (unsigned int i = 0; i < dofs_per_cell; ++i)
324 prolongation_matrices[level]->set(dof_indices_child[i],
325 dofs_per_cell,
326 dof_indices_parent.data(),
327 &prolongation(i, 0),
328 true);
329 }
330 }
331 prolongation_matrices[level]->compress(VectorOperation::insert);
332 }
333
334 this->fill_and_communicate_copy_indices(dof_handler);
335}
336
337
338
339template <typename VectorType>
340void
342{
343 for (unsigned int level = 0; level < prolongation_matrices.size(); ++level)
344 {
345 os << "Level " << level << std::endl;
346 prolongation_matrices[level]->print(os);
347 os << std::endl;
348 }
349}
350
351
352
353template <typename VectorType>
354std::size_t
356{
358 for (unsigned int i = 0; i < prolongation_matrices.size(); ++i)
359 result += prolongation_matrices[i]->memory_consumption() +
360 prolongation_sparsities[i]->memory_consumption();
361
362 return result;
363}
364
365
366// explicit instantiation
367#include "multigrid/mg_transfer_prebuilt.inst"
368
369
*  x_component_mask set(0, true)
const std::vector< std::pair< size_type, number > > * get_constraint_entries(const size_type line_n) const
size_type n_constraints() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const IndexSet & locally_owned_mg_dofs(const unsigned int level) const
const Triangulation< dim, spacedim > & get_triangulation() const
types::global_dof_index n_dofs() const
MPI_Comm get_mpi_communicator() const
bool has_level_dofs() const
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
const IndexSet & row_index_set() const
void reinit(const size_type m, const size_type n, const IndexSet &rowset=IndexSet())
unsigned int n_dofs_per_cell() const
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const
size_type n() const
bool is_boundary_index(const unsigned int level, const types::global_dof_index index) const
bool have_boundary_indices() const
const AffineConstraints< double > & get_level_constraints(const unsigned int level) const
std::size_t memory_consumption() const
virtual void restrict_and_add(const unsigned int from_level, VectorType &dst, const VectorType &src) const override
void build(const DoFHandler< dim, spacedim > &dof_handler)
std::size_t memory_consumption() const
MGTransferPrebuilt()=default
virtual void prolongate(const unsigned int to_level, VectorType &dst, const VectorType &src) const override
void print_matrices(std::ostream &os) const
void initialize_constraints(const MGConstrainedDoFs &mg_constrained_dofs)
virtual unsigned int n_global_levels() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
unsigned int level
Definition grid_out.cc:4642
IteratorRange< cell_iterator > cell_iterators_on_level(const unsigned int level) const
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcMessage(std::string arg1)
IndexSet extract_locally_relevant_level_dofs(const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level)
void distribute_sparsity_pattern(DynamicSparsityPattern &dsp, const IndexSet &locally_owned_rows, const MPI_Comm mpi_comm, const IndexSet &locally_relevant_rows)
static void reinit(Matrix &matrix, Sparsity &sparsity, int level, const SparsityPatternType &sp, const DoFHandler< dim, spacedim > &)
Definition mg_transfer.h:56