Reference documentation for deal.II version 8.4.2
mg_transfer_component.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2003 - 2015 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/logstream.h>
18 #include <deal.II/base/function.h>
19 
20 #include <deal.II/lac/vector.h>
21 #include <deal.II/lac/block_vector.h>
22 #include <deal.II/lac/block_indices.h>
23 #include <deal.II/lac/sparse_matrix.h>
24 #include <deal.II/lac/block_sparse_matrix.h>
25 #include <deal.II/grid/tria.h>
26 #include <deal.II/grid/tria_iterator.h>
27 #include <deal.II/dofs/dof_tools.h>
28 #include <deal.II/fe/fe.h>
29 #include <deal.II/dofs/dof_accessor.h>
30 #include <deal.II/multigrid/mg_transfer_component.h>
31 #include <deal.II/multigrid/mg_transfer_component.templates.h>
32 #include <deal.II/multigrid/mg_tools.h>
33 
34 #include <algorithm>
35 #include <numeric>
36 #include <iostream>
37 
38 DEAL_II_NAMESPACE_OPEN
39 
40 
41 namespace
42 {
77  template <int dim, typename number, int spacedim>
78  void
79  reinit_vector_by_components (
80  const ::DoFHandler<dim,spacedim> &mg_dof,
82  const std::vector<bool> &sel,
83  const std::vector<unsigned int> &target_comp,
84  std::vector<std::vector<types::global_dof_index> > &ndofs)
85  {
86  std::vector<bool> selected=sel;
87  std::vector<unsigned int> target_component=target_comp;
88  const unsigned int ncomp = mg_dof.get_fe().n_components();
89 
90  // If the selected and
91  // target_component have size 0,
92  // they must be replaced by default
93  // values.
94  //
95  // Since we already made copies
96  // directly after this function was
97  // called, we use the arguments
98  // directly.
99  if (target_component.size() == 0)
100  {
101  target_component.resize(ncomp);
102  for (unsigned int i=0; i<ncomp; ++i)
103  target_component[i] = i;
104  }
105 
106  // If selected is an empty vector,
107  // all components are selected.
108  if (selected.size() == 0)
109  {
110  selected.resize(target_component.size());
111  std::fill_n (selected.begin(), ncomp, false);
112  for (unsigned int i=0; i<target_component.size(); ++i)
113  selected[target_component[i]] = true;
114  }
115 
116  Assert (selected.size() == target_component.size(),
117  ExcDimensionMismatch(selected.size(), target_component.size()));
118 
119  // Compute the number of blocks needed
120  const unsigned int n_selected
121  = std::accumulate(selected.begin(),
122  selected.end(),
123  0U);
124 
125  if (ndofs.size() == 0)
126  {
127  std::vector<std::vector<types::global_dof_index> >
128  new_dofs(mg_dof.get_triangulation().n_levels(),
129  std::vector<types::global_dof_index>(target_component.size()));
130  std::swap(ndofs, new_dofs);
131  MGTools::count_dofs_per_block (mg_dof, ndofs, target_component);
132  }
133 
134  for (unsigned int level=v.min_level();
135  level<=v.max_level(); ++level)
136  {
137  v[level].reinit(n_selected, 0);
138  unsigned int k=0;
139  for (unsigned int i=0; i<selected.size() && (k<v[level].n_blocks()); ++i)
140  {
141  if (selected[i])
142  {
143  v[level].block(k++).reinit(ndofs[level][i]);
144  }
145  v[level].collect_sizes();
146  }
147  }
148  }
149 
150 
177  template <int dim, typename number, int spacedim>
178  void
179  reinit_vector_by_components (
180  const ::DoFHandler<dim,spacedim> &mg_dof,
182  const ComponentMask &component_mask,
183  const std::vector<unsigned int> &target_component,
184  std::vector<std::vector<types::global_dof_index> > &ndofs)
185  {
186  Assert (component_mask.represents_n_components(target_component.size()),
187  ExcMessage ("The component mask does not have the correct size."));
188 
189  unsigned int selected_block = 0;
190  for (unsigned int i=0; i<target_component.size(); ++i)
191  if (component_mask[i])
192  selected_block = target_component[i];
193 
194  if (ndofs.size() == 0)
195  {
196  std::vector<std::vector<types::global_dof_index> >
197  new_dofs(mg_dof.get_triangulation().n_levels(),
198  std::vector<types::global_dof_index>(target_component.size()));
199  std::swap(ndofs, new_dofs);
200  MGTools::count_dofs_per_block (mg_dof, ndofs,
201  target_component);
202  }
203 
204  for (unsigned int level=v.min_level();
205  level<=v.max_level(); ++level)
206  {
207  v[level].reinit(ndofs[level][selected_block]);
208  }
209  }
210 }
211 
212 
213 template <typename number>
214 template <int dim, class InVector, int spacedim>
215 void
217  const DoFHandler<dim,spacedim> &mg_dof_handler,
219  const InVector &src) const
220 {
221  dst=0;
222 
223  Assert(sizes.size()==mg_dof_handler.get_triangulation().n_levels(),
224  ExcMatricesNotBuilt());
225 
226  reinit_vector_by_components(mg_dof_handler, dst,
227  mg_component_mask,
228  mg_target_component, sizes);
229 
230  // traverse the grid top-down
231  // (i.e. starting with the most
232  // refined grid). this way, we can
233  // always get that part of one
234  // level of the output vector which
235  // corresponds to a region which is
236  // more refined, by restriction of
237  // the respective vector on the
238  // next finer level, which we then
239  // already have built.
240 
241  bool first = true;
242  for (unsigned int level=mg_dof_handler.get_triangulation().n_levels(); level!=0;)
243  {
244  --level;
245 
246  typedef std::vector<std::pair<types::global_dof_index, unsigned int> >::const_iterator IT;
247  for (IT i=copy_to_and_from_indices[level].begin();
248  i != copy_to_and_from_indices[level].end(); ++i)
249  dst[level](i->second) = src(i->first);
250  // for that part of the level
251  // which is further refined:
252  // get the defect by
253  // restriction of the defect on
254  // one level higher
255  if (!first)
256  restrict_and_add (level+1, dst[level], dst[level+1]);
257  first = false;
258  }
259 }
260 
261 
262 template <int dim, int spacedim>
264  const DoFHandler<dim,spacedim> &,
265  const DoFHandler<dim,spacedim> &mg_dof)
266 {
267  // Fill target component with
268  // standard values (identity) if it
269  // is empty
270  if (target_component.size() == 0)
271  {
272  target_component.resize(mg_dof.get_fe().n_components());
273  for (unsigned int i=0; i<target_component.size(); ++i)
274  target_component[i] = i;
275  }
276  else
277  {
278  // otherwise, check it for consistency
279  Assert (target_component.size() == mg_dof.get_fe().n_components(),
280  ExcDimensionMismatch(target_component.size(),
281  mg_dof.get_fe().n_components()));
282 
283  for (unsigned int i=0; i<target_component.size(); ++i)
284  {
285  Assert(i<target_component.size(),
286  ExcIndexRange(i,0,target_component.size()));
287  }
288  }
289  // Do the same for the multilevel
290  // components. These may be
291  // different.
292  if (mg_target_component.size() == 0)
293  {
294  mg_target_component.resize(mg_dof.get_fe().n_components());
295  for (unsigned int i=0; i<mg_target_component.size(); ++i)
296  mg_target_component[i] = target_component[i];
297  }
298  else
299  {
300  Assert (mg_target_component.size() == mg_dof.get_fe().n_components(),
301  ExcDimensionMismatch(mg_target_component.size(),
302  mg_dof.get_fe().n_components()));
303 
304  for (unsigned int i=0; i<mg_target_component.size(); ++i)
305  {
306  Assert(i<mg_target_component.size(),
307  ExcIndexRange(i,0,mg_target_component.size()));
308  }
309  }
310 
311  const FiniteElement<dim> &fe = mg_dof.get_fe();
312 
313  // Effective number of components
314  // is the maximum entry in
315  // mg_target_component. This
316  // assumes that the values in that
317  // vector don't have holes.
318  const unsigned int n_components =
319  *std::max_element(mg_target_component.begin(), mg_target_component.end()) + 1;
320  const unsigned int dofs_per_cell = fe.dofs_per_cell;
321  const unsigned int n_levels = mg_dof.get_triangulation().n_levels();
322 
324  ExcMessage ("Component mask has wrong size."));
325 
326  // Compute the lengths of all blocks
327  sizes.resize(n_levels);
328  for (unsigned int l=0; l<n_levels; ++l)
329  sizes[l].resize(n_components);
330 
332 
333  // Fill some index vectors
334  // for later use.
336  // Compute start indices from sizes
337  for (unsigned int l=0; l<mg_component_start.size(); ++l)
338  {
340  for (unsigned int i=0; i<mg_component_start[l].size(); ++i)
341  {
343  mg_component_start[l][i] = k;
344  k += t;
345  }
346  }
347 
348  component_start.resize(*std::max_element (target_component.begin(),
349  target_component.end()) + 1);
350  DoFTools::
351  count_dofs_per_block (mg_dof, component_start, target_component);
352 
354  for (unsigned int i=0; i<component_start.size(); ++i)
355  {
357  component_start[i] = k;
358  k += t;
359  }
360 
361  // Build index vectors for
362  // copy_to_mg and
363  // copy_from_mg. These vectors must
364  // be prebuilt, since the
365  // get_dof_indices functions are
366  // too slow
367 
368  copy_to_and_from_indices.resize(n_levels);
369 
370 // Building the prolongation matrices starts here!
371 
372  // reset the size of the array of
373  // matrices. call resize(0) first,
374  // in order to delete all elements
375  // and clear their memory. then
376  // repopulate these arrays
377  //
378  // note that on resize(0), the
379  // shared_ptr class takes care of
380  // deleting the object it points to
381  // by itself
382  prolongation_matrices.resize (0);
383  prolongation_sparsities.resize (0);
384 
385  for (unsigned int i=0; i<n_levels-1; ++i)
386  {
387  prolongation_sparsities
388  .push_back (std_cxx11::shared_ptr<BlockSparsityPattern> (new BlockSparsityPattern));
390  .push_back (std_cxx11::shared_ptr<BlockSparseMatrix<double> > (new BlockSparseMatrix<double>));
391  }
392 
393  // two fields which will store the
394  // indices of the multigrid dofs
395  // for a cell and one of its children
396  std::vector<types::global_dof_index> dof_indices_parent (dofs_per_cell);
397  std::vector<types::global_dof_index> dof_indices_child (dofs_per_cell);
398 
399  // for each level: first build the
400  // sparsity pattern of the matrices
401  // and then build the matrices
402  // themselves. note that we only
403  // need to take care of cells on
404  // the coarser level which have
405  // children
406  for (unsigned int level=0; level<n_levels-1; ++level)
407  {
408  // reset the dimension of the
409  // structure. note that for
410  // the number of entries per
411  // row, the number of parent
412  // dofs coupling to a child dof
413  // is necessary. this, is the
414  // number of degrees of freedom
415  // per cell
416  prolongation_sparsities[level]->reinit (n_components, n_components);
417  for (unsigned int i=0; i<n_components; ++i)
418  for (unsigned int j=0; j<n_components; ++j)
419  if (i==j)
420  prolongation_sparsities[level]->block(i,j)
421  .reinit(sizes[level+1][i],
422  sizes[level][j],
423  dofs_per_cell+1);
424  else
425  prolongation_sparsities[level]->block(i,j)
426  .reinit(sizes[level+1][i],
427  sizes[level][j],
428  0);
429 
430  prolongation_sparsities[level]->collect_sizes();
431 
432  for (typename DoFHandler<dim,spacedim>::cell_iterator cell=mg_dof.begin(level);
433  cell != mg_dof.end(level); ++cell)
434  if (cell->has_children())
435  {
436  cell->get_mg_dof_indices (dof_indices_parent);
437 
438  for (unsigned int child=0; child<cell->n_children(); ++child)
439  {
440  // set an alias to the
441  // prolongation matrix for
442  // this child
443  const FullMatrix<double> &prolongation
444  = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
445 
446  cell->child(child)->get_mg_dof_indices (dof_indices_child);
447 
448  // now tag the entries in the
449  // matrix which will be used
450  // for this pair of parent/child
451  for (unsigned int i=0; i<dofs_per_cell; ++i)
452  for (unsigned int j=0; j<dofs_per_cell; ++j)
453  if (prolongation(i,j) != 0)
454  {
455  const unsigned int icomp
456  = fe.system_to_component_index(i).first;
457  const unsigned int jcomp
458  = fe.system_to_component_index(j).first;
459  if ((icomp==jcomp) && mg_component_mask[icomp])
460  prolongation_sparsities[level]->add(dof_indices_child[i],
461  dof_indices_parent[j]);
462  };
463  };
464  };
465  prolongation_sparsities[level]->compress ();
466 
467  prolongation_matrices[level]->reinit (*prolongation_sparsities[level]);
468  // now actually build the matrices
469  for (typename DoFHandler<dim,spacedim>::cell_iterator cell=mg_dof.begin(level);
470  cell != mg_dof.end(level); ++cell)
471  if (cell->has_children())
472  {
473  cell->get_mg_dof_indices (dof_indices_parent);
474 
475  for (unsigned int child=0; child<cell->n_children(); ++child)
476  {
477  // set an alias to the
478  // prolongation matrix for
479  // this child
480  const FullMatrix<double> &prolongation
481  = mg_dof.get_fe().get_prolongation_matrix (child, cell->refinement_case());
482 
483  cell->child(child)->get_mg_dof_indices (dof_indices_child);
484 
485  // now set the entries in the
486  // matrix
487  for (unsigned int i=0; i<dofs_per_cell; ++i)
488  for (unsigned int j=0; j<dofs_per_cell; ++j)
489  if (prolongation(i,j) != 0)
490  {
491  const unsigned int icomp = fe.system_to_component_index(i).first;
492  const unsigned int jcomp = fe.system_to_component_index(j).first;
493  if ((icomp==jcomp) && mg_component_mask[icomp])
494  prolongation_matrices[level]->set(dof_indices_child[i],
495  dof_indices_parent[j],
496  prolongation(i,j));
497  }
498  }
499  }
500  }
501  // impose boundary conditions
502  // but only in the column of
503  // the prolongation matrix
504  //TODO: this way is not very efficient
505 
506  if (boundary_indices.size() != 0)
507  {
508  std::vector<std::vector<types::global_dof_index> >
509  dofs_per_component(mg_dof.get_triangulation().n_levels(),
510  std::vector<types::global_dof_index>(n_components));
511 
512  MGTools::count_dofs_per_block (mg_dof, dofs_per_component, mg_target_component);
513  for (unsigned int level=0; level<n_levels-1; ++level)
514  {
515  if (boundary_indices[level].size() == 0)
516  continue;
517 
518  for (unsigned int iblock=0; iblock<n_components; ++iblock)
519  for (unsigned int jblock=0; jblock<n_components; ++jblock)
520  if (iblock==jblock)
521  {
522  const types::global_dof_index n_dofs = prolongation_matrices[level]->block(iblock,jblock).m();
523  for (types::global_dof_index i=0; i<n_dofs; ++i)
524  {
525  SparseMatrix<double>::iterator anfang = prolongation_matrices[level]->block(iblock,jblock).begin(i),
526  ende = prolongation_matrices[level]->block(iblock,jblock).end(i);
527  for (; anfang != ende; ++anfang)
528  {
529  const types::global_dof_index column_number = anfang->column();
530 
531  //convert global indices into local ones
532  const BlockIndices block_indices_coarse (dofs_per_component[level]);
533  const types::global_dof_index global_j = block_indices_coarse.local_to_global(iblock, column_number);
534 
535  std::set<types::global_dof_index>::const_iterator found_dof =
536  boundary_indices[level].find(global_j);
537 
538  const bool is_boundary_index =
539  (found_dof != boundary_indices[level].end());
540 
541  if (is_boundary_index)
542  {
543  prolongation_matrices[level]->block(iblock,jblock)
544  .set(i,column_number,0);
545  }
546  }
547  }
548  }
549  }
550  }
551 }
552 
553 
554 template <typename number>
555 template <int dim, int spacedim>
557  const DoFHandler<dim,spacedim> &dof,
558  const DoFHandler<dim,spacedim> &mg_dof,
559  unsigned int select,
560  unsigned int mg_select,
561  const std::vector<unsigned int> &t_component,
562  const std::vector<unsigned int> &mg_t_component,
563  const std::vector<std::set<types::global_dof_index> > &bdry_indices)
564 {
565  const FiniteElement<dim> &fe = mg_dof.get_fe();
566  unsigned int ncomp = mg_dof.get_fe().n_components();
567 
568  target_component = t_component;
569  mg_target_component = mg_t_component;
570  boundary_indices = bdry_indices;
571 
572  selected_component = select;
573  mg_selected_component = mg_select;
574 
575  {
576  std::vector<bool> tmp(ncomp, false);
577  for (unsigned int c=0; c<ncomp; ++c)
578  if (t_component[c] == selected_component)
579  tmp[c] = true;
580  component_mask = ComponentMask(tmp);
581  }
582 
583  {
584  std::vector<bool> tmp(ncomp, false);
585  for (unsigned int c=0; c<ncomp; ++c)
586  if (mg_t_component[c] == mg_selected_component)
587  tmp[c] = true;
589  }
590 
591  // If components are renumbered,
592  // find the first original
593  // component corresponding to the
594  // target component.
595  for (unsigned int i=0; i<target_component.size(); ++i)
596  {
597  if (target_component[i] == select)
598  {
599  selected_component = i;
600  break;
601  }
602  }
603 
604  for (unsigned int i=0; i<mg_target_component.size(); ++i)
605  {
606  if (mg_target_component[i] == mg_select)
607  {
608  mg_selected_component = i;
609  break;
610  }
611  }
612 
614 
615  interface_dofs.resize(mg_dof.get_triangulation().n_levels());
616  for (unsigned int l=0; l<mg_dof.get_triangulation().n_levels(); ++l)
617  {
618  interface_dofs[l].clear();
619  interface_dofs[l].set_size(mg_dof.n_dofs(l));
620  }
621  MGTools::extract_inner_interface_dofs(mg_dof, interface_dofs);
622 
623  // use a temporary vector to create the
624  // relation between global and level dofs
625  std::vector<types::global_dof_index> temp_copy_indices;
626  std::vector<types::global_dof_index> global_dof_indices (fe.dofs_per_cell);
627  std::vector<types::global_dof_index> level_dof_indices (fe.dofs_per_cell);
628  for (int level=dof.get_triangulation().n_levels()-1; level>=0; --level)
629  {
630  copy_to_and_from_indices[level].clear();
632  level_cell = mg_dof.begin_active(level);
634  level_end = mg_dof.end_active(level);
635 
636  temp_copy_indices.resize (0);
637  temp_copy_indices.resize (mg_dof.n_dofs(level), numbers::invalid_dof_index);
638 
639  // Compute coarse level right hand side
640  // by restricting from fine level.
641  for (; level_cell!=level_end; ++level_cell)
642  {
643  // get the dof numbers of
644  // this cell for the global
645  // and the level-wise
646  // numbering
647  level_cell->get_dof_indices(global_dof_indices);
648  level_cell->get_mg_dof_indices (level_dof_indices);
649 
650  for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
651  {
652  const unsigned int component
653  = fe.system_to_component_index(i).first;
654  if (component_mask[component] &&
655  !interface_dofs[level].is_element(level_dof_indices[i]))
656  {
657  const types::global_dof_index level_start
658  = mg_component_start[level][mg_target_component[component]];
659  const types::global_dof_index global_start
660  = component_start[target_component[component]];
661  temp_copy_indices[level_dof_indices[i]-level_start] =
662  global_dof_indices[i] - global_start;
663  }
664  }
665  }
666 
667  // write indices from vector into the map from
668  // global to level dofs
669  const types::global_dof_index n_active_dofs =
670  std::count_if (temp_copy_indices.begin(), temp_copy_indices.end(),
671  std::bind2nd(std::not_equal_to<types::global_dof_index>(),
673  copy_to_and_from_indices[level].resize (n_active_dofs);
674  types::global_dof_index counter = 0;
675  for (types::global_dof_index i=0; i<temp_copy_indices.size(); ++i)
676  if (temp_copy_indices[i] != numbers::invalid_dof_index)
677  copy_to_and_from_indices[level][counter++] =
678  std::pair<types::global_dof_index, unsigned int> (temp_copy_indices[i], i);
679  Assert (counter == n_active_dofs, ExcInternalError());
680  }
681 }
682 
683 
684 
685 // explicit instantiations
686 #include "mg_transfer_component.inst"
687 
688 
689 DEAL_II_NAMESPACE_CLOSE
void build_matrices(const DoFHandler< dim, spacedim > &dof, const DoFHandler< dim, spacedim > &mg_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 > >())
cell_iterator begin(const unsigned int level=0) const
Definition: dof_handler.cc:833
std::vector< std::set< types::global_dof_index > > boundary_indices
::ExceptionBase & ExcMessage(std::string arg1)
cell_iterator end() const
Definition: dof_handler.cc:861
Auxiliary class aiding in the handling of block structures like in BlockVector or FESystem...
Definition: block_indices.h:54
bool represents_n_components(const unsigned int n) const
ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:221
std::vector< std_cxx11::shared_ptr< BlockSparseMatrix< double > > > prolongation_matrices
const FiniteElement< dim, spacedim > & get_fe() const
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: dof_handler.cc:845
ActiveSelector::cell_iterator cell_iterator
Definition: dof_handler.h:249
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:294
std::vector< types::global_dof_index > component_start
active_cell_iterator end_active(const unsigned int level) const
Definition: dof_handler.cc:883
std::vector< std::vector< std::pair< types::global_dof_index, unsigned int > > > copy_to_and_from_indices
types::global_dof_index n_dofs() const
size_type local_to_global(const unsigned int block, const size_type index) const
const unsigned int dofs_per_cell
Definition: fe_base.h:283
std::vector< unsigned int > mg_target_component
void do_copy_to_mg(const DoFHandler< dim, spacedim > &mg_dof, MGLevelObject< Vector< number > > &dst, const InVector &src) const
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
Definition: fe.h:2742
void count_dofs_per_block(const DoFHandlerType &dof, std::vector< types::global_dof_index > &dofs_per_block, const std::vector< unsigned int > &target_block=std::vector< unsigned int >())
Definition: dof_tools.cc:1661
unsigned int n_components() const
void count_dofs_per_block(const DoFHandlerType &dof_handler, std::vector< std::vector< types::global_dof_index > > &dofs_per_block, std::vector< unsigned int > target_block=std::vector< unsigned int >())
Definition: mg_tools.cc:1069
void extract_inner_interface_dofs(const DoFHandler< dim, spacedim > &mg_dof_handler, std::vector< IndexSet > &interface_dofs)
Definition: mg_tools.cc:1485
const Triangulation< dim, spacedim > & get_triangulation() const
std::vector< std::vector< types::global_dof_index > > mg_component_start
const types::global_dof_index invalid_dof_index
Definition: types.h:178
void build_matrices(const DoFHandler< dim, spacedim > &dof, const DoFHandler< dim, spacedim > &mg_dof)
std::vector< std::vector< types::global_dof_index > > sizes