deal.II version GIT relicensing-6934-g0e4b96b350 2026-10-20 03:10: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_component.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
29#include <deal.II/lac/vector.h>
30
33#include <deal.II/multigrid/mg_transfer_component.templates.h>
34
35#include <algorithm>
36#include <iostream>
37#include <numeric>
38
40
41
42namespace
43{
70 template <int dim, typename number, int spacedim>
71 void
72 reinit_vector_by_components(
73 const DoFHandler<dim, spacedim> &mg_dof,
75 const ComponentMask &component_mask,
76 const std::vector<unsigned int> &target_component,
77 std::vector<std::vector<types::global_dof_index>> &ndofs)
78 {
79 Assert(component_mask.represents_n_components(target_component.size()),
80 ExcMessage("The component mask does not have the correct size."));
81
82 unsigned int selected_block = 0;
83 for (unsigned int i = 0; i < target_component.size(); ++i)
84 if (component_mask[i])
85 selected_block = target_component[i];
86
87 if (ndofs.empty())
88 {
89 std::vector<std::vector<types::global_dof_index>> new_dofs(
90 mg_dof.get_triangulation().n_levels(),
91 std::vector<types::global_dof_index>(target_component.size()));
92 std::swap(ndofs, new_dofs);
93 MGTools::count_dofs_per_block(mg_dof, ndofs, target_component);
94 }
95
96 for (unsigned int level = v.min_level(); level <= v.max_level(); ++level)
97 {
98 v[level].reinit(ndofs[level][selected_block]);
99 }
100 }
101} // namespace
102
103
104template <typename number>
105template <int dim, class InVector, int spacedim>
106void
108 const DoFHandler<dim, spacedim> &mg_dof_handler,
110 const InVector &src) const
111{
112 dst = 0;
113
114 Assert(sizes.size() == mg_dof_handler.get_triangulation().n_levels(),
115 ExcMatricesNotBuilt());
116
117 reinit_vector_by_components(
118 mg_dof_handler, dst, mg_component_mask, mg_target_component, sizes);
119
120 // traverse the grid top-down
121 // (i.e. starting with the most
122 // refined grid). this way, we can
123 // always get that part of one
124 // level of the output vector which
125 // corresponds to a region which is
126 // more refined, by restriction of
127 // the respective vector on the
128 // next finer level, which we then
129 // already have built.
130
131 for (unsigned int level = mg_dof_handler.get_triangulation().n_levels();
132 level != 0;)
133 {
134 --level;
135
136 using IT = std::vector<
137 std::pair<types::global_dof_index, unsigned int>>::const_iterator;
138 for (IT i = copy_to_and_from_indices[level].begin();
139 i != copy_to_and_from_indices[level].end();
140 ++i)
141 dst[level](i->second) = src(i->first);
142 }
143}
144
145
146
147template <int dim, int spacedim>
148void
150{
151 // Fill target component with
152 // standard values (identity) if it
153 // is empty
154 if (target_component.empty())
155 {
156 target_component.resize(mg_dof.get_fe(0).n_components());
157 for (unsigned int i = 0; i < target_component.size(); ++i)
158 target_component[i] = i;
159 }
160 else
161 {
162 // otherwise, check it for consistency
163 Assert(target_component.size() == mg_dof.get_fe(0).n_components(),
165 mg_dof.get_fe(0).n_components()));
166
167 for (unsigned int i = 0; i < target_component.size(); ++i)
168 {
170 }
171 }
172 // Do the same for the multilevel
173 // components. These may be
174 // different.
175 if (mg_target_component.empty())
176 {
177 mg_target_component.resize(mg_dof.get_fe(0).n_components());
178 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
180 }
181 else
182 {
183 Assert(mg_target_component.size() == mg_dof.get_fe(0).n_components(),
185 mg_dof.get_fe(0).n_components()));
186
187 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
188 {
190 }
191 }
192
193 const FiniteElement<dim> &fe = mg_dof.get_fe();
194
195 // Effective number of components
196 // is the maximum entry in
197 // mg_target_component. This
198 // assumes that the values in that
199 // vector don't have holes.
200 const unsigned int n_components =
201 *std::max_element(mg_target_component.begin(), mg_target_component.end()) +
202 1;
203 const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
204 const unsigned int n_levels = mg_dof.get_triangulation().n_levels();
205
207 ExcMessage("Component mask has wrong size."));
208
209 // Compute the lengths of all blocks
210 sizes.resize(n_levels);
211 for (unsigned int l = 0; l < n_levels; ++l)
212 sizes[l].resize(n_components);
213
215
216 // Fill some index vectors
217 // for later use.
219 // Compute start indices from sizes
220 for (auto &level_components : mg_component_start)
221 {
223 for (types::global_dof_index &level_component_start : level_components)
224 {
225 const types::global_dof_index t = level_component_start;
226 level_component_start = k;
227 k += t;
228 }
229 }
230
232
234 for (types::global_dof_index &first_index : component_start)
235 {
236 const types::global_dof_index t = first_index;
237 first_index = k;
238 k += t;
239 }
240
241 // Build index vectors for
242 // copy_to_mg and
243 // copy_from_mg. These vectors must
244 // be prebuilt, since the
245 // get_dof_indices functions are
246 // too slow
247
248 copy_to_and_from_indices.resize(n_levels);
249
250 // Building the prolongation matrices starts here!
251
252 // reset the size of the array of
253 // matrices. call resize(0) first,
254 // in order to delete all elements
255 // and clear their memory. then
256 // repopulate these arrays
257 //
258 // note that on resize(0), the
259 // shared_ptr class takes care of
260 // deleting the object it points to
261 // by itself
262 prolongation_matrices.resize(0);
263 prolongation_sparsities.resize(0);
264 prolongation_matrices.reserve(n_levels - 1);
265 prolongation_sparsities.reserve(n_levels - 1);
266
267 for (unsigned int i = 0; i < n_levels - 1; ++i)
268 {
271 }
272
273 // two fields which will store the
274 // indices of the multigrid dofs
275 // for a cell and one of its children
276 std::vector<types::global_dof_index> dof_indices_parent(dofs_per_cell);
277 std::vector<types::global_dof_index> dof_indices_child(dofs_per_cell);
278
279 // for each level: first build the
280 // sparsity pattern of the matrices
281 // and then build the matrices
282 // themselves. note that we only
283 // need to take care of cells on
284 // the coarser level which have
285 // children
286 for (unsigned int level = 0; level < n_levels - 1; ++level)
287 {
288 // reset the dimension of the
289 // structure. note that for
290 // the number of entries per
291 // row, the number of parent
292 // dofs coupling to a child dof
293 // is necessary. this, is the
294 // number of degrees of freedom
295 // per cell
296 prolongation_sparsities[level]->reinit(n_components, n_components);
297 for (unsigned int i = 0; i < n_components; ++i)
298 for (unsigned int j = 0; j < n_components; ++j)
299 if (i == j)
300 prolongation_sparsities[level]->block(i, j).reinit(
301 sizes[level + 1][i], sizes[level][j], dofs_per_cell + 1);
302 else
303 prolongation_sparsities[level]->block(i, j).reinit(
304 sizes[level + 1][i], sizes[level][j], 0);
305
306 prolongation_sparsities[level]->collect_sizes();
307
309 mg_dof.begin(level);
310 cell != mg_dof.end(level);
311 ++cell)
312 if (cell->has_children())
313 {
314 cell->get_mg_dof_indices(dof_indices_parent);
315
316 for (unsigned int child = 0; child < cell->n_children(); ++child)
317 {
318 // set an alias to the
319 // prolongation matrix for
320 // this child
321 const FullMatrix<double> &prolongation =
323 child, cell->refinement_case());
324
325 cell->child(child)->get_mg_dof_indices(dof_indices_child);
326
327 // now tag the entries in the
328 // matrix which will be used
329 // for this pair of parent/child
330 for (unsigned int i = 0; i < dofs_per_cell; ++i)
331 for (unsigned int j = 0; j < dofs_per_cell; ++j)
332 if (prolongation(i, j) != 0)
333 {
334 const unsigned int icomp =
335 fe.system_to_component_index(i).first;
336 const unsigned int jcomp =
337 fe.system_to_component_index(j).first;
338 if ((icomp == jcomp) && mg_component_mask[icomp])
340 dof_indices_child[i], dof_indices_parent[j]);
341 }
342 }
343 }
344 prolongation_sparsities[level]->compress();
345
347 // now actually build the matrices
349 mg_dof.begin(level);
350 cell != mg_dof.end(level);
351 ++cell)
352 if (cell->has_children())
353 {
354 cell->get_mg_dof_indices(dof_indices_parent);
355
356 for (unsigned int child = 0; child < cell->n_children(); ++child)
357 {
358 // set an alias to the
359 // prolongation matrix for
360 // this child
361 const FullMatrix<double> &prolongation =
363 child, cell->refinement_case());
364
365 cell->child(child)->get_mg_dof_indices(dof_indices_child);
366
367 // now set the entries in the
368 // matrix
369 for (unsigned int i = 0; i < dofs_per_cell; ++i)
370 for (unsigned int j = 0; j < dofs_per_cell; ++j)
371 if (prolongation(i, j) != 0)
372 {
373 const unsigned int icomp =
374 fe.system_to_component_index(i).first;
375 const unsigned int jcomp =
376 fe.system_to_component_index(j).first;
377 if ((icomp == jcomp) && mg_component_mask[icomp])
379 dof_indices_child[i],
380 dof_indices_parent[j],
381 prolongation(i, j));
382 }
383 }
384 }
385 }
386 // impose boundary conditions
387 // but only in the column of
388 // the prolongation matrix
389 // TODO: this way is not very efficient
390
391 if (boundary_indices.size() != 0)
392 {
393 std::vector<std::vector<types::global_dof_index>> dofs_per_component(
394 mg_dof.get_triangulation().n_levels(),
395 std::vector<types::global_dof_index>(n_components));
396
398 dofs_per_component,
400 for (unsigned int level = 0; level < n_levels - 1; ++level)
401 {
402 if (boundary_indices[level].empty())
403 continue;
404
405 for (unsigned int iblock = 0; iblock < n_components; ++iblock)
406 for (unsigned int jblock = 0; jblock < n_components; ++jblock)
407 if (iblock == jblock)
408 {
409 const types::global_dof_index n_dofs =
410 prolongation_matrices[level]->block(iblock, jblock).m();
411 for (types::global_dof_index i = 0; i < n_dofs; ++i)
412 {
415 ->block(iblock, jblock)
416 .begin(i),
418 ->block(iblock, jblock)
419 .end(i);
420 for (; begin != end; ++begin)
421 {
422 const types::global_dof_index column_number =
423 begin->column();
424
425 // convert global indices into local ones
426 const BlockIndices block_indices_coarse(
427 dofs_per_component[level]);
428 const types::global_dof_index global_j =
429 block_indices_coarse.local_to_global(iblock,
430 column_number);
431
432 std::set<types::global_dof_index>::const_iterator
433 found_dof = boundary_indices[level].find(global_j);
434
435 const bool is_boundary_index =
436 (found_dof != boundary_indices[level].end());
437
438 if (is_boundary_index)
439 {
441 ->block(iblock, jblock)
442 .set(i, column_number, 0);
443 }
444 }
445 }
446 }
447 }
448 }
449}
450
451
452
453template <typename number>
454template <int dim, int spacedim>
455void
457 const DoFHandler<dim, spacedim> &mg_dof,
458 unsigned int select,
459 unsigned int mg_select,
460 const std::vector<unsigned int> &t_component,
461 const std::vector<unsigned int> &mg_t_component,
462 const std::vector<std::set<types::global_dof_index>> &bdry_indices)
463{
464 const FiniteElement<dim> &fe = mg_dof.get_fe();
465 unsigned int ncomp = mg_dof.get_fe(0).n_components();
466
467 target_component = t_component;
468 mg_target_component = mg_t_component;
469 boundary_indices = bdry_indices;
470
471 selected_component = select;
472 mg_selected_component = mg_select;
473
474 {
475 std::vector<bool> tmp(ncomp, false);
476 for (unsigned int c = 0; c < ncomp; ++c)
477 if (t_component[c] == selected_component)
478 tmp[c] = true;
479 component_mask = ComponentMask(tmp);
480 }
481
482 {
483 std::vector<bool> tmp(ncomp, false);
484 for (unsigned int c = 0; c < ncomp; ++c)
485 if (mg_t_component[c] == mg_selected_component)
486 tmp[c] = true;
487 mg_component_mask = ComponentMask(tmp);
488 }
489
490 // If components are renumbered,
491 // find the first original
492 // component corresponding to the
493 // target component.
494 for (unsigned int i = 0; i < target_component.size(); ++i)
495 {
496 if (target_component[i] == select)
497 {
498 selected_component = i;
499 break;
500 }
501 }
502
503 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
504 {
505 if (mg_target_component[i] == mg_select)
506 {
507 mg_selected_component = i;
508 break;
509 }
510 }
511
513
514 interface_dofs.resize(mg_dof.get_triangulation().n_levels());
515 for (unsigned int l = 0; l < mg_dof.get_triangulation().n_levels(); ++l)
516 {
517 interface_dofs[l].clear();
518 interface_dofs[l].set_size(mg_dof.n_dofs(l));
519 }
520 MGTools::extract_inner_interface_dofs(mg_dof, interface_dofs);
521
522 // use a temporary vector to create the
523 // relation between global and level dofs
524 std::vector<types::global_dof_index> temp_copy_indices;
525 std::vector<types::global_dof_index> global_dof_indices(fe.n_dofs_per_cell());
526 std::vector<types::global_dof_index> level_dof_indices(fe.n_dofs_per_cell());
527 for (int level = mg_dof.get_triangulation().n_levels() - 1; level >= 0;
528 --level)
529 {
530 copy_to_and_from_indices[level].clear();
532 mg_dof.begin_active(level);
533 const typename DoFHandler<dim, spacedim>::active_cell_iterator level_end =
534 mg_dof.end_active(level);
535
536 temp_copy_indices.resize(0);
537 temp_copy_indices.resize(mg_dof.n_dofs(level),
539
540 // Compute coarse level right hand side
541 // by restricting from fine level.
542 for (; level_cell != level_end; ++level_cell)
543 {
544 // get the dof numbers of
545 // this cell for the global
546 // and the level-wise
547 // numbering
548 level_cell->get_dof_indices(global_dof_indices);
549 level_cell->get_mg_dof_indices(level_dof_indices);
550
551 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
552 {
553 const unsigned int component =
554 fe.system_to_component_index(i).first;
555 if (component_mask[component] &&
556 !interface_dofs[level].is_element(level_dof_indices[i]))
557 {
558 const types::global_dof_index level_start =
559 mg_component_start[level][mg_target_component[component]];
560 const types::global_dof_index global_start =
561 component_start[target_component[component]];
562 temp_copy_indices[level_dof_indices[i] - level_start] =
563 global_dof_indices[i] - global_start;
564 }
565 }
566 }
567
568 // write indices from vector into the map from
569 // global to level dofs
570 const types::global_dof_index n_active_dofs =
571 std::count_if(temp_copy_indices.begin(),
572 temp_copy_indices.end(),
573 [](const types::global_dof_index index) {
574 return index != numbers::invalid_dof_index;
575 });
576 copy_to_and_from_indices[level].resize(n_active_dofs);
577 types::global_dof_index counter = 0;
578 for (types::global_dof_index i = 0; i < temp_copy_indices.size(); ++i)
579 if (temp_copy_indices[i] != numbers::invalid_dof_index)
580 copy_to_and_from_indices[level][counter++] =
581 std::pair<types::global_dof_index, unsigned int>(
582 temp_copy_indices[i], i);
583 Assert(counter == n_active_dofs, ExcInternalError());
584 }
585}
586
587
588
589// explicit instantiations
590#include "multigrid/mg_transfer_component.inst"
591
592
*  iterator end()
*  *  iterator begin()
*  x_component_mask set(0, true)
size_type local_to_global(const unsigned int block, const size_type index) const
bool represents_n_components(const unsigned int n) const
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
types::global_dof_index n_dofs() const
cell_iterator begin(const unsigned int level=0) const
unsigned int n_dofs_per_cell() const
unsigned int n_components() const
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const
std::vector< unsigned int > mg_target_component
std::vector< unsigned int > target_component
std::vector< types::global_dof_index > component_start
std::vector< std::shared_ptr< BlockSparseMatrix< double > > > prolongation_matrices
std::vector< std::vector< std::pair< types::global_dof_index, unsigned int > > > copy_to_and_from_indices
std::vector< std::vector< types::global_dof_index > > mg_component_start
std::vector< std::shared_ptr< BlockSparsityPattern > > prolongation_sparsities
void build(const DoFHandler< dim, spacedim > &dof_handler)
std::vector< std::vector< types::global_dof_index > > sizes
std::vector< std::set< types::global_dof_index > > boundary_indices
void do_copy_to_mg(const DoFHandler< dim, spacedim > &mg_dof, MGLevelObject< Vector< number > > &dst, const InVector &src) const
void build(const DoFHandler< dim, spacedim > &dof, unsigned int selected, unsigned int mg_selected, const std::vector< unsigned int > &target_component=std::vector< unsigned int >(), const std::vector< unsigned int > &mg_target_component=std::vector< unsigned int >(), const std::vector< std::set< types::global_dof_index > > &boundary_indices=std::vector< std::set< types::global_dof_index > >())
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
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
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 extract_inner_interface_dofs(const DoFHandler< dim, spacedim > &mg_dof_handler, std::vector< IndexSet > &interface_dofs)
Definition mg_tools.cc:1431
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
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259