deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20: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_block.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
15
18
19#include <deal.II/fe/fe.h>
20
21#include <deal.II/grid/tria.h>
23
27#include <deal.II/lac/vector.h>
28
31#include <deal.II/multigrid/mg_transfer_block.templates.h>
32
33#include <algorithm>
34#include <iostream>
35#include <numeric>
36#include <utility>
37
39
40namespace
41{
49 template <int dim, typename number, int spacedim>
50 void
51 reinit_vector_by_blocks(
52 const DoFHandler<dim, spacedim> &dof_handler,
54 const std::vector<bool> &sel,
55 std::vector<std::vector<types::global_dof_index>> &ndofs)
56 {
57 std::vector<bool> selected = sel;
58 // Compute the number of blocks needed
59 const unsigned int n_selected =
60 std::accumulate(selected.begin(), selected.end(), 0u);
61
62 if (ndofs.empty())
63 {
64 std::vector<std::vector<types::global_dof_index>> new_dofs(
65 dof_handler.get_triangulation().n_levels(),
66 std::vector<types::global_dof_index>(selected.size()));
67 std::swap(ndofs, new_dofs);
68 MGTools::count_dofs_per_block(dof_handler, ndofs);
69 }
70
71 for (unsigned int level = v.min_level(); level <= v.max_level(); ++level)
72 {
73 v[level].reinit(n_selected, 0);
74 unsigned int k = 0;
75 for (unsigned int i = 0;
76 i < selected.size() && (k < v[level].n_blocks());
77 ++i)
78 {
79 if (selected[i])
80 {
81 v[level].block(k++).reinit(ndofs[level][i]);
82 }
83 v[level].collect_sizes();
84 }
85 }
86 }
87
88
95 template <int dim, typename number, int spacedim>
96 void
97 reinit_vector_by_blocks(
98 const DoFHandler<dim, spacedim> &dof_handler,
100 const unsigned int selected_block,
101 std::vector<std::vector<types::global_dof_index>> &ndofs)
102 {
103 const unsigned int n_blocks = dof_handler.get_fe().n_blocks();
104 AssertIndexRange(selected_block, n_blocks);
105
106 std::vector<bool> selected(n_blocks, false);
107 selected[selected_block] = true;
108
109 if (ndofs.empty())
110 {
111 std::vector<std::vector<types::global_dof_index>> new_dofs(
112 dof_handler.get_triangulation().n_levels(),
113 std::vector<types::global_dof_index>(selected.size()));
114 std::swap(ndofs, new_dofs);
115 MGTools::count_dofs_per_block(dof_handler, ndofs);
116 }
117
118 for (unsigned int level = v.min_level(); level <= v.max_level(); ++level)
119 {
120 v[level].reinit(ndofs[level][selected_block]);
121 }
122 }
123} // namespace
124
125
126template <typename number>
127template <int dim, typename number2, int spacedim>
128void
130 const DoFHandler<dim, spacedim> &dof_handler,
132 const BlockVector<number2> &src) const
133{
134 reinit_vector_by_blocks(dof_handler, dst, selected_block, sizes);
135 // For MGTransferBlockSelect, the
136 // multilevel block is always the
137 // first, since only one block is
138 // selected.
139 for (unsigned int level = dof_handler.get_triangulation().n_levels();
140 level != 0;)
141 {
142 --level;
143 for (IT i = copy_indices[selected_block][level].begin();
144 i != copy_indices[selected_block][level].end();
145 ++i)
146 dst[level](i->second) = src.block(selected_block)(i->first);
147 }
148}
149
150
151
152template <typename number>
153template <int dim, typename number2, int spacedim>
154void
156 const DoFHandler<dim, spacedim> &dof_handler,
158 const Vector<number2> &src) const
159{
160 reinit_vector_by_blocks(dof_handler, dst, selected_block, sizes);
161 // For MGTransferBlockSelect, the
162 // multilevel block is always the
163 // first, since only one block is selected.
164 for (unsigned int level = dof_handler.get_triangulation().n_levels();
165 level != 0;)
166 {
167 --level;
168 for (IT i = copy_indices[selected_block][level].begin();
169 i != copy_indices[selected_block][level].end();
170 ++i)
171 dst[level](i->second) = src(i->first);
172 }
173}
174
175
176
177template <typename number>
178template <int dim, typename number2, int spacedim>
179void
181 const DoFHandler<dim, spacedim> &dof_handler,
183 const BlockVector<number2> &src) const
184{
185 reinit_vector_by_blocks(dof_handler, dst, selected, sizes);
186 for (unsigned int level = dof_handler.get_triangulation().n_levels();
187 level != 0;)
188 {
189 --level;
190 for (unsigned int block = 0; block < selected.size(); ++block)
191 if (selected[block])
192 for (IT i = copy_indices[block][level].begin();
193 i != copy_indices[block][level].end();
194 ++i)
195 dst[level].block(mg_block[block])(i->second) =
196 src.block(block)(i->first);
197 }
198}
199
200
201
202template <int dim, int spacedim>
203void
205{
206 const FiniteElement<dim> &fe = dof_handler.get_fe();
207 const unsigned int n_blocks = fe.n_blocks();
208 const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
209 const unsigned int n_levels = dof_handler.get_triangulation().n_levels();
210
211 Assert(selected.size() == n_blocks,
212 ExcDimensionMismatch(selected.size(), n_blocks));
213
214 // Compute the mapping between real
215 // blocks and blocks used for
216 // multigrid computations.
217 mg_block.resize(n_blocks);
218 n_mg_blocks = 0;
219 for (unsigned int i = 0; i < n_blocks; ++i)
220 if (selected[i])
221 mg_block[i] = n_mg_blocks++;
222 else
224
225 // Compute the lengths of all blocks
226 sizes.clear();
227 sizes.resize(n_levels, std::vector<types::global_dof_index>(fe.n_blocks()));
229
230 // Fill some index vectors
231 // for later use.
233 // Compute start indices from sizes
234 for (auto &level_blocks : mg_block_start)
235 {
237 for (types::global_dof_index &level_block_start : level_blocks)
238 {
239 const types::global_dof_index t = level_block_start;
240 level_block_start = k;
241 k += t;
242 }
243 }
244
246 static_cast<const DoFHandler<dim, spacedim> &>(dof_handler));
247
249 for (types::global_dof_index &first_index : block_start)
250 {
251 const types::global_dof_index t = first_index;
252 first_index = k;
253 k += t;
254 }
255 // Build index vectors for
256 // copy_to_mg and
257 // copy_from_mg. These vectors must
258 // be prebuilt, since the
259 // get_dof_indices functions are
260 // too slow
261 copy_indices.resize(n_blocks);
262 for (unsigned int block = 0; block < n_blocks; ++block)
263 if (selected[block])
264 copy_indices[block].resize(n_levels);
265
266 // Building the prolongation matrices starts here!
267
268 // reset the size of the array of
269 // matrices. call resize(0) first,
270 // in order to delete all elements
271 // and clear their memory. then
272 // repopulate these arrays
273 //
274 // note that on resize(0), the
275 // shared_ptr class takes care of
276 // deleting the object it points to
277 // by itself
278 prolongation_matrices.resize(0);
279 prolongation_sparsities.resize(0);
280 prolongation_matrices.reserve(n_levels - 1);
281 prolongation_sparsities.reserve(n_levels - 1);
282
283 for (unsigned int i = 0; i < n_levels - 1; ++i)
284 {
287 }
288
289 // two fields which will store the
290 // indices of the multigrid dofs
291 // for a cell and one of its children
292 std::vector<types::global_dof_index> dof_indices_parent(dofs_per_cell);
293 std::vector<types::global_dof_index> dof_indices_child(dofs_per_cell);
294
295 // for each level: first build the
296 // sparsity pattern of the matrices
297 // and then build the matrices
298 // themselves. note that we only
299 // need to take care of cells on
300 // the coarser level which have
301 // children
302
303 for (unsigned int level = 0; level < n_levels - 1; ++level)
304 {
305 // reset the dimension of the
306 // structure. note that for
307 // the number of entries per
308 // row, the number of parent
309 // dofs coupling to a child dof
310 // is necessary. this, is the
311 // number of degrees of freedom
312 // per cell
313 prolongation_sparsities[level]->reinit(n_blocks, n_blocks);
314 for (unsigned int i = 0; i < n_blocks; ++i)
315 for (unsigned int j = 0; j < n_blocks; ++j)
316 if (i == j)
317 prolongation_sparsities[level]->block(i, j).reinit(
318 sizes[level + 1][i], sizes[level][j], dofs_per_cell + 1);
319 else
320 prolongation_sparsities[level]->block(i, j).reinit(
321 sizes[level + 1][i], sizes[level][j], 0);
322
323 prolongation_sparsities[level]->collect_sizes();
324
326 dof_handler.begin(level);
327 cell != dof_handler.end(level);
328 ++cell)
329 if (cell->has_children())
330 {
331 cell->get_mg_dof_indices(dof_indices_parent);
332
333 Assert(cell->n_children() ==
336 for (unsigned int child = 0; child < cell->n_children(); ++child)
337 {
338 // set an alias to the
339 // prolongation matrix for
340 // this child
341 const FullMatrix<double> &prolongation =
342 dof_handler.get_fe().get_prolongation_matrix(
343 child, cell->refinement_case());
344
345 cell->child(child)->get_mg_dof_indices(dof_indices_child);
346
347 // now tag the entries in the
348 // matrix which will be used
349 // for this pair of parent/child
350 for (unsigned int i = 0; i < dofs_per_cell; ++i)
351 for (unsigned int j = 0; j < dofs_per_cell; ++j)
352 if (prolongation(i, j) != 0)
353 {
354 const unsigned int icomp =
355 fe.system_to_block_index(i).first;
356 const unsigned int jcomp =
357 fe.system_to_block_index(j).first;
358 if ((icomp == jcomp) && selected[icomp])
360 dof_indices_child[i], dof_indices_parent[j]);
361 }
362 }
363 }
364 prolongation_sparsities[level]->compress();
365
367 // now actually build the matrices
369 dof_handler.begin(level);
370 cell != dof_handler.end(level);
371 ++cell)
372 if (cell->has_children())
373 {
374 cell->get_mg_dof_indices(dof_indices_parent);
375
376 Assert(cell->n_children() ==
379 for (unsigned int child = 0; child < cell->n_children(); ++child)
380 {
381 // set an alias to the
382 // prolongation matrix for
383 // this child
384 const FullMatrix<double> &prolongation =
385 dof_handler.get_fe().get_prolongation_matrix(
386 child, cell->refinement_case());
387
388 cell->child(child)->get_mg_dof_indices(dof_indices_child);
389
390 // now set the entries in the
391 // matrix
392 for (unsigned int i = 0; i < dofs_per_cell; ++i)
393 for (unsigned int j = 0; j < dofs_per_cell; ++j)
394 if (prolongation(i, j) != 0)
395 {
396 const unsigned int icomp =
397 fe.system_to_block_index(i).first;
398 const unsigned int jcomp =
399 fe.system_to_block_index(j).first;
400 if ((icomp == jcomp) && selected[icomp])
402 dof_indices_child[i],
403 dof_indices_parent[j],
404 prolongation(i, j));
405 }
406 }
407 }
408 }
409 // impose boundary conditions
410 // but only in the column of
411 // the prolongation matrix
412 if (mg_constrained_dofs != nullptr &&
414 {
415 std::vector<types::global_dof_index> constrain_indices;
416 std::vector<std::vector<bool>> constraints_per_block(n_blocks);
417 for (int level = n_levels - 2; level >= 0; --level)
418 {
420 0)
421 continue;
422
423 // need to delete all the columns in the
424 // matrix that are on the boundary. to achieve
425 // this, create an array as long as there are
426 // matrix columns, and find which columns we
427 // need to filter away.
428 constrain_indices.resize(0);
429 constrain_indices.resize(prolongation_matrices[level]->n(), 0);
433 for (; dof != endd; ++dof)
434 constrain_indices[*dof] = 1;
435
436 unsigned int index = 0;
437 for (unsigned int block = 0; block < n_blocks; ++block)
438 {
439 const types::global_dof_index n_dofs =
440 prolongation_matrices[level]->block(block, block).m();
441 constraints_per_block[block].resize(0);
442 constraints_per_block[block].resize(n_dofs, false);
443 for (types::global_dof_index i = 0; i < n_dofs; ++i, ++index)
444 constraints_per_block[block][i] =
445 (constrain_indices[index] == 1);
446
447 for (types::global_dof_index i = 0; i < n_dofs; ++i)
448 {
450 start_row = prolongation_matrices[level]
451 ->block(block, block)
452 .begin(i),
453 end_row =
454 prolongation_matrices[level]->block(block, block).end(i);
455 for (; start_row != end_row; ++start_row)
456 {
457 if (constraints_per_block[block][start_row->column()])
458 start_row->value() = 0.;
459 }
460 }
461 }
462 }
463 }
464}
465
466template <typename number>
467template <int dim, int spacedim>
468void
470 const DoFHandler<dim, spacedim> &dof_handler,
471 unsigned int select)
472{
473 const FiniteElement<dim> &fe = dof_handler.get_fe();
474 unsigned int n_blocks = dof_handler.get_fe().n_blocks();
475
476 selected_block = select;
477 selected.resize(n_blocks, false);
478 selected[select] = true;
479
480 MGTransferBlockBase::build(dof_handler);
481
482 std::vector<types::global_dof_index> temp_copy_indices;
483 std::vector<types::global_dof_index> global_dof_indices(fe.n_dofs_per_cell());
484 std::vector<types::global_dof_index> level_dof_indices(fe.n_dofs_per_cell());
485
486 for (int level = dof_handler.get_triangulation().n_levels() - 1; level >= 0;
487 --level)
488 {
490 dof_handler.begin_active(level);
491 const typename DoFHandler<dim, spacedim>::active_cell_iterator level_end =
492 dof_handler.end_active(level);
493
494 temp_copy_indices.resize(0);
495 temp_copy_indices.resize(sizes[level][selected_block],
497
498 // Compute coarse level right hand side
499 // by restricting from fine level.
500 for (; level_cell != level_end; ++level_cell)
501 {
502 // get the dof numbers of
503 // this cell for the global
504 // and the level-wise
505 // numbering
506 level_cell->get_dof_indices(global_dof_indices);
507 level_cell->get_mg_dof_indices(level_dof_indices);
508
509 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
510 {
511 const unsigned int block = fe.system_to_block_index(i).first;
512 if (selected[block])
513 {
514 if (mg_constrained_dofs != nullptr)
515 {
516 if (!mg_constrained_dofs->at_refinement_edge(
517 level, level_dof_indices[i]))
518 temp_copy_indices[level_dof_indices[i] -
519 mg_block_start[level][block]] =
520 global_dof_indices[i] - block_start[block];
521 }
522 else
523 temp_copy_indices[level_dof_indices[i] -
524 mg_block_start[level][block]] =
525 global_dof_indices[i] - block_start[block];
526 }
527 }
528 }
529
530 // now all the active dofs got a valid entry,
531 // the other ones have an invalid entry. Count
532 // the invalid entries and then resize the
533 // copy_indices object. Then, insert the pairs
534 // of global index and level index into
535 // copy_indices.
536 const types::global_dof_index n_active_dofs =
537 std::count_if(temp_copy_indices.begin(),
538 temp_copy_indices.end(),
539 [](const types::global_dof_index index) {
540 return index != numbers::invalid_dof_index;
541 });
542 copy_indices[selected_block][level].resize(n_active_dofs);
543 types::global_dof_index counter = 0;
544 for (types::global_dof_index i = 0; i < temp_copy_indices.size(); ++i)
545 if (temp_copy_indices[i] != numbers::invalid_dof_index)
546 copy_indices[selected_block][level][counter++] =
547 std::pair<types::global_dof_index, unsigned int>(
548 temp_copy_indices[i], i);
549 Assert(counter == n_active_dofs, ExcInternalError());
550 }
551}
552
553
554template <typename number>
555template <int dim, int spacedim>
556void
558 const std::vector<bool> &sel)
559{
560 const FiniteElement<dim> &fe = dof_handler.get_fe();
561 unsigned int n_blocks = dof_handler.get_fe().n_blocks();
562
563 if (sel.size() != 0)
564 {
565 Assert(sel.size() == n_blocks,
566 ExcDimensionMismatch(sel.size(), n_blocks));
567 selected = sel;
568 }
569 if (selected.empty())
570 selected = std::vector<bool>(n_blocks, true);
571
572 MGTransferBlockBase::build(dof_handler);
573
574 std::vector<std::vector<types::global_dof_index>> temp_copy_indices(n_blocks);
575 std::vector<types::global_dof_index> global_dof_indices(fe.n_dofs_per_cell());
576 std::vector<types::global_dof_index> level_dof_indices(fe.n_dofs_per_cell());
577 for (int level = dof_handler.get_triangulation().n_levels() - 1; level >= 0;
578 --level)
579 {
581 dof_handler.begin_active(level);
582 const typename DoFHandler<dim, spacedim>::active_cell_iterator level_end =
583 dof_handler.end_active(level);
584
585 for (unsigned int block = 0; block < n_blocks; ++block)
586 if (selected[block])
587 {
588 temp_copy_indices[block].resize(0);
589 temp_copy_indices[block].resize(sizes[level][block],
591 }
592
593 // Compute coarse level right hand side
594 // by restricting from fine level.
595 for (; level_cell != level_end; ++level_cell)
596 {
597 // get the dof numbers of
598 // this cell for the global
599 // and the level-wise
600 // numbering
601 level_cell->get_dof_indices(global_dof_indices);
602 level_cell->get_mg_dof_indices(level_dof_indices);
603
604 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
605 {
606 const unsigned int block = fe.system_to_block_index(i).first;
607 if (selected[block])
608 temp_copy_indices[block][level_dof_indices[i] -
609 mg_block_start[level][block]] =
610 global_dof_indices[i] - block_start[block];
611 }
612 }
613
614 for (unsigned int block = 0; block < n_blocks; ++block)
615 if (selected[block])
616 {
617 const types::global_dof_index n_active_dofs =
618 std::count_if(temp_copy_indices[block].begin(),
619 temp_copy_indices[block].end(),
620 [](const types::global_dof_index index) {
621 return index != numbers::invalid_dof_index;
622 });
623 copy_indices[block][level].resize(n_active_dofs);
624 types::global_dof_index counter = 0;
625 for (types::global_dof_index i = 0;
626 i < temp_copy_indices[block].size();
627 ++i)
628 if (temp_copy_indices[block][i] != numbers::invalid_dof_index)
629 copy_indices[block][level][counter++] =
630 std::pair<types::global_dof_index, unsigned int>(
631 temp_copy_indices[block][i], i);
632 Assert(counter == n_active_dofs, ExcInternalError());
633 }
634 }
635}
636
637
638
639// explicit instantiations
640#include "multigrid/mg_transfer_block.inst"
641
642
*  iterator end()
*  *  iterator begin()
BlockType & block(const unsigned int i)
cell_iterator end() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const Triangulation< dim, spacedim > & get_triangulation() const
active_cell_iterator begin_active(const unsigned int level=0) const
active_cell_iterator end_active(const unsigned int level) const
cell_iterator begin(const unsigned int level=0) const
unsigned int n_dofs_per_cell() const
unsigned int n_blocks() const
std::pair< unsigned int, types::global_dof_index > system_to_block_index(const unsigned int component) 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_elements() const
Definition index_set.h:1917
ElementIterator begin() const
Definition index_set.h:1693
ElementIterator end() const
Definition index_set.h:1705
bool have_boundary_indices() const
const IndexSet & get_boundary_indices(const unsigned int level) const
std::vector< unsigned int > mg_block
std::vector< std::vector< types::global_dof_index > > sizes
void build(const DoFHandler< dim, spacedim > &dof_handler)
std::vector< bool > selected
std::vector< types::global_dof_index > block_start
std::vector< std::shared_ptr< BlockSparseMatrix< double > > > prolongation_matrices
std::vector< std::shared_ptr< BlockSparsityPattern > > prolongation_sparsities
ObserverPointer< const MGConstrainedDoFs, MGTransferBlockBase > mg_constrained_dofs
std::vector< std::vector< types::global_dof_index > > mg_block_start
std::vector< std::vector< std::vector< std::pair< unsigned int, unsigned int > > > > copy_indices
void copy_to_mg(const DoFHandler< dim, spacedim > &dof_handler, MGLevelObject< Vector< number > > &dst, const Vector< number2 > &src) const
void build(const DoFHandler< dim, spacedim > &dof_handler, unsigned int selected)
void build(const DoFHandler< dim, spacedim > &dof_handler, const std::vector< bool > &selected)
void copy_to_mg(const DoFHandler< dim, spacedim > &dof_handler, MGLevelObject< BlockVector< number > > &dst, const BlockVector< number2 > &src) const
unsigned int n_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
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
typename ActiveSelector::cell_iterator cell_iterator
typename ActiveSelector::active_cell_iterator active_cell_iterator
std::vector< types::global_dof_index > count_dofs_per_fe_block(const DoFHandler< dim, spacedim > &dof, const std::vector< unsigned int > &target_block=std::vector< unsigned int >())
void count_dofs_per_block(const DoFHandler< dim, spacedim > &dof_handler, std::vector< std::vector< types::global_dof_index > > &dofs_per_block, std::vector< unsigned int > target_block={})
Definition mg_tools.cc:1144
std::enable_if_t< IsBlockVector< VectorType >::value, unsigned int > n_blocks(const VectorType &vector)
Definition operators.h:47
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
constexpr unsigned int invalid_unsigned_int
Definition types.h:228