deal.II version 9.8.0
\(\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{
76 template <int dim, typename number, int spacedim>
77 void
78 reinit_vector_by_components(
79 const DoFHandler<dim, spacedim> &mg_dof,
81 const std::vector<bool> &sel,
82 const std::vector<unsigned int> &target_comp,
83 std::vector<std::vector<types::global_dof_index>> &ndofs)
84 {
85 std::vector<bool> selected = sel;
86 std::vector<unsigned int> target_component = target_comp;
87 const unsigned int ncomp = mg_dof.get_fe(0).n_components();
88
89 // If the selected and
90 // target_component have size 0,
91 // they must be replaced by default
92 // values.
93 //
94 // Since we already made copies
95 // directly after this function was
96 // called, we use the arguments
97 // directly.
98 if (target_component.empty())
99 {
100 target_component.resize(ncomp);
101 for (unsigned int i = 0; i < ncomp; ++i)
102 target_component[i] = i;
103 }
104
105 // If selected is an empty vector,
106 // all components are selected.
107 if (selected.empty())
108 {
109 selected.resize(target_component.size());
110 std::fill_n(selected.begin(), ncomp, false);
111 for (const unsigned int component : target_component)
112 selected[component] = true;
113 }
114
115 Assert(selected.size() == target_component.size(),
116 ExcDimensionMismatch(selected.size(), target_component.size()));
117
118 // Compute the number of blocks needed
119 const unsigned int n_selected =
120 std::accumulate(selected.begin(), selected.end(), 0u);
121
122 if (ndofs.empty())
123 {
124 std::vector<std::vector<types::global_dof_index>> new_dofs(
125 mg_dof.get_triangulation().n_levels(),
126 std::vector<types::global_dof_index>(target_component.size()));
127 std::swap(ndofs, new_dofs);
128 MGTools::count_dofs_per_block(mg_dof, ndofs, target_component);
129 }
130
131 for (unsigned int level = v.min_level(); level <= v.max_level(); ++level)
132 {
133 v[level].reinit(n_selected, 0);
134 unsigned int k = 0;
135 for (unsigned int i = 0;
136 i < selected.size() && (k < v[level].n_blocks());
137 ++i)
138 {
139 if (selected[i])
140 {
141 v[level].block(k++).reinit(ndofs[level][i]);
142 }
143 v[level].collect_sizes();
144 }
145 }
146 }
147
148
175 template <int dim, typename number, int spacedim>
176 void
177 reinit_vector_by_components(
178 const DoFHandler<dim, spacedim> &mg_dof,
180 const ComponentMask &component_mask,
181 const std::vector<unsigned int> &target_component,
182 std::vector<std::vector<types::global_dof_index>> &ndofs)
183 {
184 Assert(component_mask.represents_n_components(target_component.size()),
185 ExcMessage("The component mask does not have the correct size."));
186
187 unsigned int selected_block = 0;
188 for (unsigned int i = 0; i < target_component.size(); ++i)
189 if (component_mask[i])
190 selected_block = target_component[i];
191
192 if (ndofs.empty())
193 {
194 std::vector<std::vector<types::global_dof_index>> new_dofs(
195 mg_dof.get_triangulation().n_levels(),
196 std::vector<types::global_dof_index>(target_component.size()));
197 std::swap(ndofs, new_dofs);
198 MGTools::count_dofs_per_block(mg_dof, ndofs, target_component);
199 }
200
201 for (unsigned int level = v.min_level(); level <= v.max_level(); ++level)
202 {
203 v[level].reinit(ndofs[level][selected_block]);
204 }
205 }
206} // namespace
207
208
209template <typename number>
210template <int dim, class InVector, int spacedim>
211void
213 const DoFHandler<dim, spacedim> &mg_dof_handler,
215 const InVector &src) const
216{
217 dst = 0;
218
219 Assert(sizes.size() == mg_dof_handler.get_triangulation().n_levels(),
221
222 reinit_vector_by_components(
223 mg_dof_handler, dst, mg_component_mask, mg_target_component, sizes);
224
225 // traverse the grid top-down
226 // (i.e. starting with the most
227 // refined grid). this way, we can
228 // always get that part of one
229 // level of the output vector which
230 // corresponds to a region which is
231 // more refined, by restriction of
232 // the respective vector on the
233 // next finer level, which we then
234 // already have built.
235
236 for (unsigned int level = mg_dof_handler.get_triangulation().n_levels();
237 level != 0;)
238 {
239 --level;
240
241 using IT = std::vector<
242 std::pair<types::global_dof_index, unsigned int>>::const_iterator;
243 for (IT i = copy_to_and_from_indices[level].begin();
244 i != copy_to_and_from_indices[level].end();
245 ++i)
246 dst[level](i->second) = src(i->first);
247 }
248}
249
250
251
252template <int dim, int spacedim>
253void
255{
256 // Fill target component with
257 // standard values (identity) if it
258 // is empty
259 if (target_component.empty())
260 {
261 target_component.resize(mg_dof.get_fe(0).n_components());
262 for (unsigned int i = 0; i < target_component.size(); ++i)
263 target_component[i] = i;
264 }
265 else
266 {
267 // otherwise, check it for consistency
268 Assert(target_component.size() == mg_dof.get_fe(0).n_components(),
270 mg_dof.get_fe(0).n_components()));
271
272 for (unsigned int i = 0; i < target_component.size(); ++i)
273 {
275 }
276 }
277 // Do the same for the multilevel
278 // components. These may be
279 // different.
280 if (mg_target_component.empty())
281 {
282 mg_target_component.resize(mg_dof.get_fe(0).n_components());
283 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
285 }
286 else
287 {
288 Assert(mg_target_component.size() == mg_dof.get_fe(0).n_components(),
290 mg_dof.get_fe(0).n_components()));
291
292 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
293 {
295 }
296 }
297
298 const FiniteElement<dim> &fe = mg_dof.get_fe();
299
300 // Effective number of components
301 // is the maximum entry in
302 // mg_target_component. This
303 // assumes that the values in that
304 // vector don't have holes.
305 const unsigned int n_components =
306 *std::max_element(mg_target_component.begin(), mg_target_component.end()) +
307 1;
308 const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
309 const unsigned int n_levels = mg_dof.get_triangulation().n_levels();
310
311 Assert(mg_component_mask.represents_n_components(fe.n_components()),
312 ExcMessage("Component mask has wrong size."));
313
314 // Compute the lengths of all blocks
315 sizes.resize(n_levels);
316 for (unsigned int l = 0; l < n_levels; ++l)
317 sizes[l].resize(n_components);
318
320
321 // Fill some index vectors
322 // for later use.
324 // Compute start indices from sizes
325 for (auto &level_components : mg_component_start)
326 {
328 for (types::global_dof_index &level_component_start : level_components)
329 {
330 const types::global_dof_index t = level_component_start;
331 level_component_start = k;
332 k += t;
333 }
334 }
335
337
339 for (types::global_dof_index &first_index : component_start)
340 {
341 const types::global_dof_index t = first_index;
342 first_index = k;
343 k += t;
344 }
345
346 // Build index vectors for
347 // copy_to_mg and
348 // copy_from_mg. These vectors must
349 // be prebuilt, since the
350 // get_dof_indices functions are
351 // too slow
352
353 copy_to_and_from_indices.resize(n_levels);
354
355 // Building the prolongation matrices starts here!
356
357 // reset the size of the array of
358 // matrices. call resize(0) first,
359 // in order to delete all elements
360 // and clear their memory. then
361 // repopulate these arrays
362 //
363 // note that on resize(0), the
364 // shared_ptr class takes care of
365 // deleting the object it points to
366 // by itself
367 prolongation_matrices.resize(0);
368 prolongation_sparsities.resize(0);
369 prolongation_matrices.reserve(n_levels - 1);
370 prolongation_sparsities.reserve(n_levels - 1);
371
372 for (unsigned int i = 0; i < n_levels - 1; ++i)
373 {
376 }
377
378 // two fields which will store the
379 // indices of the multigrid dofs
380 // for a cell and one of its children
381 std::vector<types::global_dof_index> dof_indices_parent(dofs_per_cell);
382 std::vector<types::global_dof_index> dof_indices_child(dofs_per_cell);
383
384 // for each level: first build the
385 // sparsity pattern of the matrices
386 // and then build the matrices
387 // themselves. note that we only
388 // need to take care of cells on
389 // the coarser level which have
390 // children
391 for (unsigned int level = 0; level < n_levels - 1; ++level)
392 {
393 // reset the dimension of the
394 // structure. note that for
395 // the number of entries per
396 // row, the number of parent
397 // dofs coupling to a child dof
398 // is necessary. this, is the
399 // number of degrees of freedom
400 // per cell
401 prolongation_sparsities[level]->reinit(n_components, n_components);
402 for (unsigned int i = 0; i < n_components; ++i)
403 for (unsigned int j = 0; j < n_components; ++j)
404 if (i == j)
405 prolongation_sparsities[level]->block(i, j).reinit(
406 sizes[level + 1][i], sizes[level][j], dofs_per_cell + 1);
407 else
408 prolongation_sparsities[level]->block(i, j).reinit(
409 sizes[level + 1][i], sizes[level][j], 0);
410
411 prolongation_sparsities[level]->collect_sizes();
412
414 mg_dof.begin(level);
415 cell != mg_dof.end(level);
416 ++cell)
417 if (cell->has_children())
418 {
419 cell->get_mg_dof_indices(dof_indices_parent);
420
421 for (unsigned int child = 0; child < cell->n_children(); ++child)
422 {
423 // set an alias to the
424 // prolongation matrix for
425 // this child
426 const FullMatrix<double> &prolongation =
428 child, cell->refinement_case());
429
430 cell->child(child)->get_mg_dof_indices(dof_indices_child);
431
432 // now tag the entries in the
433 // matrix which will be used
434 // for this pair of parent/child
435 for (unsigned int i = 0; i < dofs_per_cell; ++i)
436 for (unsigned int j = 0; j < dofs_per_cell; ++j)
437 if (prolongation(i, j) != 0)
438 {
439 const unsigned int icomp =
440 fe.system_to_component_index(i).first;
441 const unsigned int jcomp =
442 fe.system_to_component_index(j).first;
443 if ((icomp == jcomp) && mg_component_mask[icomp])
444 prolongation_sparsities[level]->add(
445 dof_indices_child[i], dof_indices_parent[j]);
446 }
447 }
448 }
449 prolongation_sparsities[level]->compress();
450
451 prolongation_matrices[level]->reinit(*prolongation_sparsities[level]);
452 // now actually build the matrices
454 mg_dof.begin(level);
455 cell != mg_dof.end(level);
456 ++cell)
457 if (cell->has_children())
458 {
459 cell->get_mg_dof_indices(dof_indices_parent);
460
461 for (unsigned int child = 0; child < cell->n_children(); ++child)
462 {
463 // set an alias to the
464 // prolongation matrix for
465 // this child
466 const FullMatrix<double> &prolongation =
468 child, cell->refinement_case());
469
470 cell->child(child)->get_mg_dof_indices(dof_indices_child);
471
472 // now set the entries in the
473 // matrix
474 for (unsigned int i = 0; i < dofs_per_cell; ++i)
475 for (unsigned int j = 0; j < dofs_per_cell; ++j)
476 if (prolongation(i, j) != 0)
477 {
478 const unsigned int icomp =
479 fe.system_to_component_index(i).first;
480 const unsigned int jcomp =
481 fe.system_to_component_index(j).first;
482 if ((icomp == jcomp) && mg_component_mask[icomp])
483 prolongation_matrices[level]->set(
484 dof_indices_child[i],
485 dof_indices_parent[j],
486 prolongation(i, j));
487 }
488 }
489 }
490 }
491 // impose boundary conditions
492 // but only in the column of
493 // the prolongation matrix
494 // TODO: this way is not very efficient
495
496 if (boundary_indices.size() != 0)
497 {
498 std::vector<std::vector<types::global_dof_index>> dofs_per_component(
499 mg_dof.get_triangulation().n_levels(),
500 std::vector<types::global_dof_index>(n_components));
501
503 dofs_per_component,
505 for (unsigned int level = 0; level < n_levels - 1; ++level)
506 {
507 if (boundary_indices[level].empty())
508 continue;
509
510 for (unsigned int iblock = 0; iblock < n_components; ++iblock)
511 for (unsigned int jblock = 0; jblock < n_components; ++jblock)
512 if (iblock == jblock)
513 {
514 const types::global_dof_index n_dofs =
515 prolongation_matrices[level]->block(iblock, jblock).m();
516 for (types::global_dof_index i = 0; i < n_dofs; ++i)
517 {
520 ->block(iblock, jblock)
521 .begin(i),
523 ->block(iblock, jblock)
524 .end(i);
525 for (; begin != end; ++begin)
526 {
527 const types::global_dof_index column_number =
528 begin->column();
529
530 // convert global indices into local ones
531 const BlockIndices block_indices_coarse(
532 dofs_per_component[level]);
533 const types::global_dof_index global_j =
534 block_indices_coarse.local_to_global(iblock,
535 column_number);
536
537 std::set<types::global_dof_index>::const_iterator
538 found_dof = boundary_indices[level].find(global_j);
539
540 const bool is_boundary_index =
541 (found_dof != boundary_indices[level].end());
542
543 if (is_boundary_index)
544 {
546 ->block(iblock, jblock)
547 .set(i, column_number, 0);
548 }
549 }
550 }
551 }
552 }
553 }
554}
555
556
557
558template <typename number>
559template <int dim, int spacedim>
560void
562 const DoFHandler<dim, spacedim> &mg_dof,
563 unsigned int select,
564 unsigned int mg_select,
565 const std::vector<unsigned int> &t_component,
566 const std::vector<unsigned int> &mg_t_component,
567 const std::vector<std::set<types::global_dof_index>> &bdry_indices)
568{
569 const FiniteElement<dim> &fe = mg_dof.get_fe();
570 unsigned int ncomp = mg_dof.get_fe(0).n_components();
571
572 target_component = t_component;
573 mg_target_component = mg_t_component;
574 boundary_indices = bdry_indices;
575
577 mg_selected_component = mg_select;
578
579 {
580 std::vector<bool> tmp(ncomp, false);
581 for (unsigned int c = 0; c < ncomp; ++c)
582 if (t_component[c] == selected_component)
583 tmp[c] = true;
585 }
586
587 {
588 std::vector<bool> tmp(ncomp, false);
589 for (unsigned int c = 0; c < ncomp; ++c)
590 if (mg_t_component[c] == mg_selected_component)
591 tmp[c] = true;
593 }
594
595 // If components are renumbered,
596 // find the first original
597 // component corresponding to the
598 // target component.
599 for (unsigned int i = 0; i < target_component.size(); ++i)
600 {
601 if (target_component[i] == select)
602 {
604 break;
605 }
606 }
607
608 for (unsigned int i = 0; i < mg_target_component.size(); ++i)
609 {
610 if (mg_target_component[i] == mg_select)
611 {
613 break;
614 }
615 }
616
618
619 interface_dofs.resize(mg_dof.get_triangulation().n_levels());
620 for (unsigned int l = 0; l < mg_dof.get_triangulation().n_levels(); ++l)
621 {
622 interface_dofs[l].clear();
623 interface_dofs[l].set_size(mg_dof.n_dofs(l));
624 }
626
627 // use a temporary vector to create the
628 // relation between global and level dofs
629 std::vector<types::global_dof_index> temp_copy_indices;
630 std::vector<types::global_dof_index> global_dof_indices(fe.n_dofs_per_cell());
631 std::vector<types::global_dof_index> level_dof_indices(fe.n_dofs_per_cell());
632 for (int level = mg_dof.get_triangulation().n_levels() - 1; level >= 0;
633 --level)
634 {
635 copy_to_and_from_indices[level].clear();
637 mg_dof.begin_active(level);
638 const typename DoFHandler<dim, spacedim>::active_cell_iterator level_end =
639 mg_dof.end_active(level);
640
641 temp_copy_indices.resize(0);
642 temp_copy_indices.resize(mg_dof.n_dofs(level),
644
645 // Compute coarse level right hand side
646 // by restricting from fine level.
647 for (; level_cell != level_end; ++level_cell)
648 {
649 // get the dof numbers of
650 // this cell for the global
651 // and the level-wise
652 // numbering
653 level_cell->get_dof_indices(global_dof_indices);
654 level_cell->get_mg_dof_indices(level_dof_indices);
655
656 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
657 {
658 const unsigned int component =
659 fe.system_to_component_index(i).first;
660 if (component_mask[component] &&
661 !interface_dofs[level].is_element(level_dof_indices[i]))
662 {
663 const types::global_dof_index level_start =
664 mg_component_start[level][mg_target_component[component]];
665 const types::global_dof_index global_start =
667 temp_copy_indices[level_dof_indices[i] - level_start] =
668 global_dof_indices[i] - global_start;
669 }
670 }
671 }
672
673 // write indices from vector into the map from
674 // global to level dofs
675 const types::global_dof_index n_active_dofs =
676 std::count_if(temp_copy_indices.begin(),
677 temp_copy_indices.end(),
678 [](const types::global_dof_index index) {
679 return index != numbers::invalid_dof_index;
680 });
681 copy_to_and_from_indices[level].resize(n_active_dofs);
683 for (types::global_dof_index i = 0; i < temp_copy_indices.size(); ++i)
684 if (temp_copy_indices[i] != numbers::invalid_dof_index)
686 std::pair<types::global_dof_index, unsigned int>(
687 temp_copy_indices[i], i);
688 Assert(counter == n_active_dofs, ExcInternalError());
689 }
690}
691
692
693
694// explicit instantiations
695#include "multigrid/mg_transfer_component.inst"
696
697
*  iterator end()
*  *  iterator begin()
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
unsigned int mg_selected_component
unsigned int selected_component
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 > >())
void select(const unsigned int component, const unsigned int mg_component=numbers::invalid_unsigned_int)
std::vector< IndexSet > interface_dofs
SparseMatrixIterators::Iterator< number, false > iterator
unsigned int n_levels() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMatricesNotBuilt()
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
std::enable_if_t< IsBlockVector< VectorType >::value, unsigned int > n_blocks(const VectorType &vector)
Definition operators.h:47
*  *  *  ScaleZFunction< dim, Number, components >::ScaleZFunction *  component(component)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:267
unsigned int global_dof_index
Definition types.h:92
*  const unsigned int dofs_per_cell