Reference documentation for deal.II version 9.0.0
mg_tools.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2018 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 #include <deal.II/base/logstream.h>
17 #include <deal.II/base/thread_management.h>
18 #include <deal.II/lac/sparsity_pattern.h>
19 #include <deal.II/lac/block_sparsity_pattern.h>
20 #include <deal.II/lac/dynamic_sparsity_pattern.h>
21 #include <deal.II/lac/sparsity_pattern.h>
22 #include <deal.II/lac/block_vector.h>
23 #include <deal.II/lac/sparse_matrix.h>
24 #include <deal.II/lac/block_sparse_matrix.h>
25 #include <deal.II/lac/block_vector.h>
26 #include <deal.II/grid/tria.h>
27 #include <deal.II/grid/tria_iterator.h>
28 #include <deal.II/dofs/dof_accessor.h>
29 #include <deal.II/multigrid/mg_tools.h>
30 #include <deal.II/multigrid/mg_base.h>
31 #include <deal.II/multigrid/mg_constrained_dofs.h>
32 #include <deal.II/base/mg_level_object.h>
33 #include <deal.II/dofs/dof_handler.h>
34 #include <deal.II/dofs/dof_tools.h>
35 #include <deal.II/fe/fe.h>
36 #include <deal.II/fe/component_mask.h>
37 #include <deal.II/numerics/matrix_tools.h>
38 
39 #include <vector>
40 #include <algorithm>
41 #include <numeric>
42 
43 DEAL_II_NAMESPACE_OPEN
44 
45 
46 namespace MGTools
47 {
48 
49 
50  // specializations for 1D
51  template <>
52  void
54  const DoFHandler<1,1> &,
55  const unsigned int,
56  std::vector<unsigned int> &,
57  const DoFTools::Coupling)
58  {
59  Assert(false, ExcNotImplemented());
60  }
61 
62 
63 
64  template <>
65  void
67  const DoFHandler<1,1> &,
68  const unsigned int,
69  std::vector<unsigned int> &,
72  {
73  Assert(false, ExcNotImplemented());
74  }
75 
76 
77 
78  template <>
79  void
81  const DoFHandler<1,2> &,
82  const unsigned int,
83  std::vector<unsigned int> &,
84  const DoFTools::Coupling)
85  {
86  Assert(false, ExcNotImplemented());
87  }
88 
89 
90  template <>
91  void
93  const DoFHandler<1,2> &,
94  const unsigned int,
95  std::vector<unsigned int> &,
98  {
99  Assert(false, ExcNotImplemented());
100  }
101 
102 
103 
104 // Template for 2D and 3D. For 1D see specialization above
105  template <int dim, int spacedim>
106  void
108  const DoFHandler<dim,spacedim> &dofs,
109  const unsigned int level,
110  std::vector<unsigned int> &row_lengths,
111  const DoFTools::Coupling flux_coupling)
112  {
113  Assert (row_lengths.size() == dofs.n_dofs(),
114  ExcDimensionMismatch(row_lengths.size(), dofs.n_dofs()));
115 
116  // Function starts here by
117  // resetting the counters.
118  std::fill(row_lengths.begin(), row_lengths.end(), 0);
119  // We need the user flags, so we
120  // save them for later restoration
121  std::vector<bool> old_flags;
122  // We need a non-constant
123  // triangulation for the user
124  // flags. Since we restore them in
125  // the end, this cast is safe.
126  Triangulation<dim,spacedim> &user_flags_triangulation =
127  const_cast<Triangulation<dim,spacedim>&> (dofs.get_triangulation());
128  user_flags_triangulation.save_user_flags(old_flags);
129  user_flags_triangulation.clear_user_flags();
130 
131  const typename DoFHandler<dim,spacedim>::cell_iterator end = dofs.end(level);
133  std::vector<types::global_dof_index> cell_indices;
134  std::vector<types::global_dof_index> neighbor_indices;
135 
136  // We loop over cells and go from
137  // cells to lower dimensional
138  // objects. This is the only way to
139  // cope with the fact, that an
140  // unknown number of cells may
141  // share an object of dimension
142  // smaller than dim-1.
143  for (cell = dofs.begin(level); cell != end; ++cell)
144  {
145  const FiniteElement<dim> &fe = cell->get_fe();
146  cell_indices.resize(fe.dofs_per_cell);
147  cell->get_mg_dof_indices(cell_indices);
148  unsigned int i = 0;
149  // First, dofs on
150  // vertices. We assume that
151  // each vertex dof couples
152  // with all dofs on
153  // adjacent grid cells.
154 
155  // Adding all dofs of the cells
156  // will add dofs of the faces
157  // of the cell adjacent to the
158  // vertex twice. Therefore, we
159  // subtract these here and add
160  // them in a loop over the
161  // faces below.
162 
163  // in 1d, faces and vertices
164  // are identical. Nevertheless,
165  // this will only work if
166  // dofs_per_face is zero and
167  // dofs_per_vertex is
168  // arbitrary, not the other way
169  // round.
170 //TODO: This assumes that even in hp context, the dofs per face coincide!
171  unsigned int increment = fe.dofs_per_cell - dim * fe.dofs_per_face;
172  while (i < fe.first_line_index)
173  row_lengths[cell_indices[i++]] += increment;
174  // From now on, if an object is
175  // a cell, its dofs only couple
176  // inside the cell. Since the
177  // faces are handled below, we
178  // have to subtract ALL faces
179  // in this case.
180 
181  // In all other cases we
182  // subtract adjacent faces to be
183  // added in the loop below.
184  increment = (dim>1)
185  ? fe.dofs_per_cell - (dim-1) * fe.dofs_per_face
187  while (i < fe.first_quad_index)
188  row_lengths[cell_indices[i++]] += increment;
189 
190  // Now quads in 2D and 3D
191  increment = (dim>2)
192  ? fe.dofs_per_cell - (dim-2) * fe.dofs_per_face
194  while (i < fe.first_hex_index)
195  row_lengths[cell_indices[i++]] += increment;
196  // Finally, cells in 3D
198  while (i < fe.dofs_per_cell)
199  row_lengths[cell_indices[i++]] += increment;
200 
201  // At this point, we have
202  // counted all dofs
203  // contributiong from cells
204  // coupled topologically to the
205  // adjacent cells, but we
206  // subtracted some faces.
207 
208  // Now, let's go by the faces
209  // and add the missing
210  // contribution as well as the
211  // flux contributions.
212  for (unsigned int iface=0; iface<GeometryInfo<dim>::faces_per_cell; ++iface)
213  {
214  bool level_boundary = cell->at_boundary(iface);
215  typename DoFHandler<dim,spacedim>::cell_iterator neighbor;
216  if (!level_boundary)
217  {
218  neighbor = cell->neighbor(iface);
219  if (static_cast<unsigned int>(neighbor->level()) != level)
220  level_boundary = true;
221  }
222 
223  if (level_boundary)
224  {
225  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
226  row_lengths[cell_indices[local_dof]] += fe.dofs_per_face;
227  continue;
228  }
229 
230  const FiniteElement<dim> &nfe = neighbor->get_fe();
231  typename DoFHandler<dim,spacedim>::face_iterator face = cell->face(iface);
232 
233  // Flux couplings are
234  // computed from both sides
235  // for simplicity.
236 
237  // The dofs on the common face
238  // will be handled below,
239  // therefore, we subtract them
240  // here.
241  if (flux_coupling != DoFTools::none)
242  {
243  const unsigned int dof_increment = nfe.dofs_per_cell - nfe.dofs_per_face;
244  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
245  row_lengths[cell_indices[local_dof]] += dof_increment;
246  }
247 
248  // Do this only once per
249  // face.
250  if (face->user_flag_set())
251  continue;
252  face->set_user_flag();
253  // At this point, we assume
254  // that each cell added its
255  // dofs minus the face to
256  // the couplings of the
257  // face dofs. Since we
258  // subtracted two faces, we
259  // have to re-add one.
260 
261  // If one side of the face
262  // is refined, all the fine
263  // face dofs couple with
264  // the coarse one.
265  neighbor_indices.resize(nfe.dofs_per_cell);
266  neighbor->get_mg_dof_indices(neighbor_indices);
267  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
268  row_lengths[cell_indices[local_dof]] += nfe.dofs_per_face;
269  for (unsigned int local_dof=0; local_dof<nfe.dofs_per_cell; ++local_dof)
270  row_lengths[neighbor_indices[local_dof]] += fe.dofs_per_face;
271  }
272  }
273  user_flags_triangulation.load_user_flags(old_flags);
274  }
275 
276 
277 // This is the template for 2D and 3D. See version for 1D above
278  template <int dim, int spacedim>
279  void
281  const DoFHandler<dim,spacedim> &dofs,
282  const unsigned int level,
283  std::vector<unsigned int> &row_lengths,
284  const Table<2,DoFTools::Coupling> &couplings,
285  const Table<2,DoFTools::Coupling> &flux_couplings)
286  {
287  Assert (row_lengths.size() == dofs.n_dofs(),
288  ExcDimensionMismatch(row_lengths.size(), dofs.n_dofs()));
289 
290  // Function starts here by
291  // resetting the counters.
292  std::fill(row_lengths.begin(), row_lengths.end(), 0);
293  // We need the user flags, so we
294  // save them for later restoration
295  std::vector<bool> old_flags;
296  // We need a non-constant
297  // triangulation for the user
298  // flags. Since we restore them in
299  // the end, this cast is safe.
300  Triangulation<dim,spacedim> &user_flags_triangulation =
301  const_cast<Triangulation<dim,spacedim>&> (dofs.get_triangulation());
302  user_flags_triangulation.save_user_flags(old_flags);
303  user_flags_triangulation.clear_user_flags();
304 
305  const typename DoFHandler<dim,spacedim>::cell_iterator end = dofs.end(level);
307  std::vector<types::global_dof_index> cell_indices;
308  std::vector<types::global_dof_index> neighbor_indices;
309 
310  // We have to translate the
311  // couplings from components to
312  // blocks, so this works for
313  // nonprimitive elements as well.
314  std::vector<Table<2, DoFTools::Coupling> > couple_cell;
315  std::vector<Table<2, DoFTools::Coupling> > couple_face;
316  DoFTools::convert_couplings_to_blocks(dofs, couplings, couple_cell);
317  DoFTools::convert_couplings_to_blocks(dofs, flux_couplings, couple_face);
318 
319  // We loop over cells and go from
320  // cells to lower dimensional
321  // objects. This is the only way to
322  // cope with the fact, that an
323  // unknown number of cells may
324  // share an object of dimension
325  // smaller than dim-1.
326  for (cell = dofs.begin_active(); cell != end; ++cell)
327  {
328  const FiniteElement<dim> &fe = cell->get_fe();
329  const unsigned int fe_index = cell->active_fe_index();
330 
331  Assert (couplings.n_rows()==fe.n_components(),
332  ExcDimensionMismatch(couplings.n_rows(), fe.n_components()));
333  Assert (couplings.n_cols()==fe.n_components(),
334  ExcDimensionMismatch(couplings.n_cols(), fe.n_components()));
335  Assert (flux_couplings.n_rows()==fe.n_components(),
336  ExcDimensionMismatch(flux_couplings.n_rows(), fe.n_components()));
337  Assert (flux_couplings.n_cols()==fe.n_components(),
338  ExcDimensionMismatch(flux_couplings.n_cols(), fe.n_components()));
339 
340  cell_indices.resize(fe.dofs_per_cell);
341  cell->get_mg_dof_indices(cell_indices);
342  unsigned int i = 0;
343  // First, dofs on
344  // vertices. We assume that
345  // each vertex dof couples
346  // with all dofs on
347  // adjacent grid cells.
348 
349  // Adding all dofs of the cells
350  // will add dofs of the faces
351  // of the cell adjacent to the
352  // vertex twice. Therefore, we
353  // subtract these here and add
354  // them in a loop over the
355  // faces below.
356 
357  // in 1d, faces and vertices
358  // are identical. Nevertheless,
359  // this will only work if
360  // dofs_per_face is zero and
361  // dofs_per_vertex is
362  // arbitrary, not the other way
363  // round.
364  unsigned int increment;
365  while (i < fe.first_line_index)
366  {
367  for (unsigned int base=0; base<fe.n_base_elements(); ++base)
368  for (unsigned int mult=0; mult<fe.element_multiplicity(base); ++mult)
369  if (couple_cell[fe_index](fe.system_to_block_index(i).first,
370  fe.first_block_of_base(base) + mult) != DoFTools::none)
371  {
372  increment = fe.base_element(base).dofs_per_cell
373  - dim * fe.base_element(base).dofs_per_face;
374  row_lengths[cell_indices[i]] += increment;
375  }
376  ++i;
377  }
378  // From now on, if an object is
379  // a cell, its dofs only couple
380  // inside the cell. Since the
381  // faces are handled below, we
382  // have to subtract ALL faces
383  // in this case.
384 
385  // In all other cases we
386  // subtract adjacent faces to be
387  // added in the loop below.
388  while (i < fe.first_quad_index)
389  {
390  for (unsigned int base=0; base<fe.n_base_elements(); ++base)
391  for (unsigned int mult=0; mult<fe.element_multiplicity(base); ++mult)
392  if (couple_cell[fe_index](fe.system_to_block_index(i).first,
393  fe.first_block_of_base(base) + mult) != DoFTools::none)
394  {
395  increment = fe.base_element(base).dofs_per_cell
396  - ((dim>1)
397  ? (dim-1)
399  * fe.base_element(base).dofs_per_face;
400  row_lengths[cell_indices[i]] += increment;
401  }
402  ++i;
403  }
404 
405  // Now quads in 2D and 3D
406  while (i < fe.first_hex_index)
407  {
408  for (unsigned int base=0; base<fe.n_base_elements(); ++base)
409  for (unsigned int mult=0; mult<fe.element_multiplicity(base); ++mult)
410  if (couple_cell[fe_index](fe.system_to_block_index(i).first,
411  fe.first_block_of_base(base) + mult) != DoFTools::none)
412  {
413  increment = fe.base_element(base).dofs_per_cell
414  - ((dim>2)
415  ? (dim-2)
417  * fe.base_element(base).dofs_per_face;
418  row_lengths[cell_indices[i]] += increment;
419  }
420  ++i;
421  }
422 
423  // Finally, cells in 3D
424  while (i < fe.dofs_per_cell)
425  {
426  for (unsigned int base=0; base<fe.n_base_elements(); ++base)
427  for (unsigned int mult=0; mult<fe.element_multiplicity(base); ++mult)
428  if (couple_cell[fe_index](fe.system_to_block_index(i).first,
429  fe.first_block_of_base(base) + mult) != DoFTools::none)
430  {
431  increment = fe.base_element(base).dofs_per_cell
433  * fe.base_element(base).dofs_per_face;
434  row_lengths[cell_indices[i]] += increment;
435  }
436  ++i;
437  }
438 
439  // At this point, we have
440  // counted all dofs
441  // contributiong from cells
442  // coupled topologically to the
443  // adjacent cells, but we
444  // subtracted some faces.
445 
446  // Now, let's go by the faces
447  // and add the missing
448  // contribution as well as the
449  // flux contributions.
450  for (unsigned int iface=0; iface<GeometryInfo<dim>::faces_per_cell; ++iface)
451  {
452  bool level_boundary = cell->at_boundary(iface);
453  typename DoFHandler<dim,spacedim>::cell_iterator neighbor;
454  if (!level_boundary)
455  {
456  neighbor = cell->neighbor(iface);
457  if (static_cast<unsigned int>(neighbor->level()) != level)
458  level_boundary = true;
459  }
460 
461  if (level_boundary)
462  {
463  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
464  row_lengths[cell_indices[local_dof]] += fe.dofs_per_face;
465  continue;
466  }
467 
468  const FiniteElement<dim> &nfe = neighbor->get_fe();
469  typename DoFHandler<dim,spacedim>::face_iterator face = cell->face(iface);
470 
471  // Flux couplings are
472  // computed from both sides
473  // for simplicity.
474 
475  // The dofs on the common face
476  // will be handled below,
477  // therefore, we subtract them
478  // here.
479  for (unsigned int base=0; base<nfe.n_base_elements(); ++base)
480  for (unsigned int mult=0; mult<nfe.element_multiplicity(base); ++mult)
481  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
482  if (couple_face[fe_index](fe.system_to_block_index(local_dof).first,
483  nfe.first_block_of_base(base) + mult) != DoFTools::none)
484  {
485  const unsigned int dof_increment = nfe.base_element(base).dofs_per_cell
486  - nfe.base_element(base).dofs_per_face;
487  row_lengths[cell_indices[local_dof]] += dof_increment;
488  }
489 
490  // Do this only once per
491  // face and not on the
492  // hanging faces.
493  if (face->user_flag_set())
494  continue;
495  face->set_user_flag();
496  // At this point, we assume
497  // that each cell added its
498  // dofs minus the face to
499  // the couplings of the
500  // face dofs. Since we
501  // subtracted two faces, we
502  // have to re-add one.
503 
504  // If one side of the face
505  // is refined, all the fine
506  // face dofs couple with
507  // the coarse one.
508 
509  // Wolfgang, do they couple
510  // with each other by
511  // constraints?
512 
513  // This will not work with
514  // different couplings on
515  // different cells.
516  neighbor_indices.resize(nfe.dofs_per_cell);
517  neighbor->get_mg_dof_indices(neighbor_indices);
518  for (unsigned int base=0; base<nfe.n_base_elements(); ++base)
519  for (unsigned int mult=0; mult<nfe.element_multiplicity(base); ++mult)
520  for (unsigned int local_dof=0; local_dof<fe.dofs_per_cell; ++local_dof)
521  if (couple_cell[fe_index](fe.system_to_component_index(local_dof).first,
522  nfe.first_block_of_base(base) + mult) != DoFTools::none)
523  row_lengths[cell_indices[local_dof]]
524  += nfe.base_element(base).dofs_per_face;
525  for (unsigned int base=0; base<fe.n_base_elements(); ++base)
526  for (unsigned int mult=0; mult<fe.element_multiplicity(base); ++mult)
527  for (unsigned int local_dof=0; local_dof<nfe.dofs_per_cell; ++local_dof)
528  if (couple_cell[fe_index](nfe.system_to_component_index(local_dof).first,
529  fe.first_block_of_base(base) + mult) != DoFTools::none)
530  row_lengths[neighbor_indices[local_dof]]
531  += fe.base_element(base).dofs_per_face;
532  }
533  }
534  user_flags_triangulation.load_user_flags(old_flags);
535  }
536 
537 
538 
539  template <typename DoFHandlerType, typename SparsityPatternType>
540  void make_sparsity_pattern (const DoFHandlerType &dof,
541  SparsityPatternType &sparsity,
542  const unsigned int level)
543  {
544  const types::global_dof_index n_dofs = dof.n_dofs(level);
545  (void)n_dofs;
546 
547  Assert (sparsity.n_rows() == n_dofs,
548  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
549  Assert (sparsity.n_cols() == n_dofs,
550  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
551 
552  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
553  std::vector<types::global_dof_index> dofs_on_this_cell(dofs_per_cell);
554  typename DoFHandlerType::cell_iterator cell = dof.begin(level),
555  endc = dof.end(level);
556  for (; cell!=endc; ++cell)
557  if (dof.get_triangulation().locally_owned_subdomain()==numbers::invalid_subdomain_id
558  || cell->level_subdomain_id()==dof.get_triangulation().locally_owned_subdomain())
559  {
560  cell->get_mg_dof_indices (dofs_on_this_cell);
561  // make sparsity pattern for this cell
562  for (unsigned int i=0; i<dofs_per_cell; ++i)
563  for (unsigned int j=0; j<dofs_per_cell; ++j)
564  sparsity.add (dofs_on_this_cell[i],
565  dofs_on_this_cell[j]);
566  }
567  }
568 
569 
570 
571  template <int dim, typename SparsityPatternType, int spacedim>
572  void
574  SparsityPatternType &sparsity,
575  const unsigned int level)
576  {
577  const types::global_dof_index n_dofs = dof.n_dofs(level);
578  (void)n_dofs;
579 
580  Assert (sparsity.n_rows() == n_dofs,
581  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
582  Assert (sparsity.n_cols() == n_dofs,
583  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
584 
585  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
586  std::vector<types::global_dof_index> dofs_on_this_cell(dofs_per_cell);
587  std::vector<types::global_dof_index> dofs_on_other_cell(dofs_per_cell);
588  typename DoFHandler<dim,spacedim>::cell_iterator cell = dof.begin(level),
589  endc = dof.end(level);
590  for (; cell!=endc; ++cell)
591  {
592  if (!cell->is_locally_owned_on_level()) continue;
593 
594  cell->get_mg_dof_indices (dofs_on_this_cell);
595  // make sparsity pattern for this cell
596  for (unsigned int i=0; i<dofs_per_cell; ++i)
597  for (unsigned int j=0; j<dofs_per_cell; ++j)
598  sparsity.add (dofs_on_this_cell[i],
599  dofs_on_this_cell[j]);
600 
601  // Loop over all interior neighbors
602  for (unsigned int face = 0;
603  face < GeometryInfo<dim>::faces_per_cell;
604  ++face)
605  {
606  bool use_face = false;
607  if ((! cell->at_boundary(face)) &&
608  (static_cast<unsigned int>(cell->neighbor_level(face)) == level))
609  use_face = true;
610  else if (cell->has_periodic_neighbor(face) &&
611  (static_cast<unsigned int>(cell->periodic_neighbor_level(face)) == level))
612  use_face = true;
613 
614  if (use_face)
615  {
617  neighbor = cell->neighbor_or_periodic_neighbor(face);
618  neighbor->get_mg_dof_indices (dofs_on_other_cell);
619  // only add one direction The other is taken care of by
620  // neighbor (except when the neighbor is not owned by the same
621  // processor)
622  for (unsigned int i=0; i<dofs_per_cell; ++i)
623  {
624  for (unsigned int j=0; j<dofs_per_cell; ++j)
625  {
626  sparsity.add (dofs_on_this_cell[i],
627  dofs_on_other_cell[j]);
628  }
629  }
630  if (neighbor->is_locally_owned_on_level() == false)
631  for (unsigned int i=0; i<dofs_per_cell; ++i)
632  for (unsigned int j=0; j<dofs_per_cell; ++j)
633  {
634  sparsity.add (dofs_on_other_cell[i],
635  dofs_on_other_cell[j]);
636  sparsity.add (dofs_on_other_cell[i],
637  dofs_on_this_cell[j]);
638  }
639  }
640  }
641  }
642  }
643 
644 
645 
646  template <int dim, typename SparsityPatternType, int spacedim>
647  void
649  SparsityPatternType &sparsity,
650  const unsigned int level)
651  {
652  Assert ((level>=1) && (level<dof.get_triangulation().n_global_levels()),
653  ExcIndexRange(level, 1, dof.get_triangulation().n_global_levels()));
654 
655  const types::global_dof_index fine_dofs = dof.n_dofs(level);
656  const types::global_dof_index coarse_dofs = dof.n_dofs(level-1);
657  (void)fine_dofs;
658  (void)coarse_dofs;
659 
660  // Matrix maps from fine level to coarse level
661 
662  Assert (sparsity.n_rows() == coarse_dofs,
663  ExcDimensionMismatch (sparsity.n_rows(), coarse_dofs));
664  Assert (sparsity.n_cols() == fine_dofs,
665  ExcDimensionMismatch (sparsity.n_cols(), fine_dofs));
666 
667  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
668  std::vector<types::global_dof_index> dofs_on_this_cell(dofs_per_cell);
669  std::vector<types::global_dof_index> dofs_on_other_cell(dofs_per_cell);
670  typename DoFHandler<dim,spacedim>::cell_iterator cell = dof.begin(level),
671  endc = dof.end(level);
672  for (; cell!=endc; ++cell)
673  {
674  if (!cell->is_locally_owned_on_level()) continue;
675 
676  cell->get_mg_dof_indices (dofs_on_this_cell);
677  // Loop over all interior neighbors
678  for (unsigned int face = 0;
679  face < GeometryInfo<dim>::faces_per_cell;
680  ++face)
681  {
682  // Neighbor is coarser
683  bool use_face = false;
684  if ((! cell->at_boundary(face)) &&
685  (static_cast<unsigned int>(cell->neighbor_level(face)) != level))
686  use_face = true;
687  else if (cell->has_periodic_neighbor(face) &&
688  (static_cast<unsigned int>(cell->periodic_neighbor_level(face)) != level))
689  use_face = true;
690 
691  if (use_face)
692  {
694  neighbor = cell->neighbor_or_periodic_neighbor(face);
695  neighbor->get_mg_dof_indices (dofs_on_other_cell);
696 
697  for (unsigned int i=0; i<dofs_per_cell; ++i)
698  {
699  for (unsigned int j=0; j<dofs_per_cell; ++j)
700  {
701  sparsity.add (dofs_on_other_cell[i],
702  dofs_on_this_cell[j]);
703  sparsity.add (dofs_on_other_cell[j],
704  dofs_on_this_cell[i]);
705  }
706  }
707  }
708  }
709  }
710  }
711 
712 
713 
714  template <int dim, typename SparsityPatternType, int spacedim>
715  void
717  SparsityPatternType &sparsity,
718  const unsigned int level,
719  const Table<2,DoFTools::Coupling> &int_mask,
720  const Table<2,DoFTools::Coupling> &flux_mask)
721  {
722  const FiniteElement<dim> &fe = dof.get_fe();
723  const types::global_dof_index n_dofs = dof.n_dofs(level);
724  const unsigned int n_comp = fe.n_components();
725  (void)n_dofs;
726  (void)n_comp;
727 
728  Assert (sparsity.n_rows() == n_dofs,
729  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
730  Assert (sparsity.n_cols() == n_dofs,
731  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
732  Assert (int_mask.n_rows() == n_comp,
733  ExcDimensionMismatch (int_mask.n_rows(), n_comp));
734  Assert (int_mask.n_cols() == n_comp,
735  ExcDimensionMismatch (int_mask.n_cols(), n_comp));
736  Assert (flux_mask.n_rows() == n_comp,
737  ExcDimensionMismatch (flux_mask.n_rows(), n_comp));
738  Assert (flux_mask.n_cols() == n_comp,
739  ExcDimensionMismatch (flux_mask.n_cols(), n_comp));
740 
741  const unsigned int total_dofs = fe.dofs_per_cell;
742  std::vector<types::global_dof_index> dofs_on_this_cell(total_dofs);
743  std::vector<types::global_dof_index> dofs_on_other_cell(total_dofs);
744  Table<2,bool> support_on_face(total_dofs, GeometryInfo<dim>::faces_per_cell);
745 
746  typename DoFHandler<dim,spacedim>::cell_iterator cell = dof.begin(level),
747  endc = dof.end(level);
748 
750  int_dof_mask = DoFTools::dof_couplings_from_component_couplings(fe, int_mask),
751  flux_dof_mask = DoFTools::dof_couplings_from_component_couplings(fe, flux_mask);
752 
753  for (unsigned int i=0; i<total_dofs; ++i)
754  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
755  support_on_face(i,f) = fe.has_support_on_face(i,f);
756 
757  // Clear user flags because we will
758  // need them. But first we save
759  // them and make sure that we
760  // restore them later such that at
761  // the end of this function the
762  // Triangulation will be in the
763  // same state as it was at the
764  // beginning of this function.
765  std::vector<bool> user_flags;
766  dof.get_triangulation().save_user_flags(user_flags);
767  const_cast<Triangulation<dim,spacedim> &>(dof.get_triangulation()).clear_user_flags ();
768 
769  for (; cell!=endc; ++cell)
770  {
771  if (!cell->is_locally_owned_on_level()) continue;
772 
773  cell->get_mg_dof_indices (dofs_on_this_cell);
774  // make sparsity pattern for this cell
775  for (unsigned int i=0; i<total_dofs; ++i)
776  for (unsigned int j=0; j<total_dofs; ++j)
777  if (int_dof_mask[i][j] != DoFTools::none)
778  sparsity.add (dofs_on_this_cell[i],
779  dofs_on_this_cell[j]);
780 
781  // Loop over all interior neighbors
782  for (unsigned int face = 0;
783  face < GeometryInfo<dim>::faces_per_cell;
784  ++face)
785  {
786  typename DoFHandler<dim,spacedim>::face_iterator cell_face = cell->face(face);
787  if (cell_face->user_flag_set ())
788  continue;
789 
790  if (cell->at_boundary (face) && !cell->has_periodic_neighbor(face))
791  {
792  for (unsigned int i=0; i<total_dofs; ++i)
793  {
794  const bool i_non_zero_i = support_on_face (i, face);
795  for (unsigned int j=0; j<total_dofs; ++j)
796  {
797  const bool j_non_zero_i = support_on_face (j, face);
798 
799  if (flux_dof_mask(i,j) == DoFTools::always)
800  sparsity.add (dofs_on_this_cell[i],
801  dofs_on_this_cell[j]);
802  if (flux_dof_mask(i,j) == DoFTools::nonzero
803  && i_non_zero_i && j_non_zero_i)
804  sparsity.add (dofs_on_this_cell[i],
805  dofs_on_this_cell[j]);
806  }
807  }
808  }
809  else
810  {
812  neighbor = cell->neighbor_or_periodic_neighbor(face);
813 
814  if (neighbor->level() < cell->level())
815  continue;
816 
817  unsigned int neighbor_face = cell->has_periodic_neighbor(face)?
818  cell->periodic_neighbor_of_periodic_neighbor(face):
819  cell->neighbor_of_neighbor(face);
820 
821  neighbor->get_mg_dof_indices (dofs_on_other_cell);
822  for (unsigned int i=0; i<total_dofs; ++i)
823  {
824  const bool i_non_zero_i = support_on_face (i, face);
825  const bool i_non_zero_e = support_on_face (i, neighbor_face);
826  for (unsigned int j=0; j<total_dofs; ++j)
827  {
828  const bool j_non_zero_i = support_on_face (j, face);
829  const bool j_non_zero_e = support_on_face (j, neighbor_face);
830  if (flux_dof_mask(i,j) == DoFTools::always)
831  {
832  sparsity.add (dofs_on_this_cell[i],
833  dofs_on_other_cell[j]);
834  sparsity.add (dofs_on_other_cell[i],
835  dofs_on_this_cell[j]);
836  sparsity.add (dofs_on_this_cell[i],
837  dofs_on_this_cell[j]);
838  sparsity.add (dofs_on_other_cell[i],
839  dofs_on_other_cell[j]);
840  }
841  if (flux_dof_mask(i,j) == DoFTools::nonzero)
842  {
843  if (i_non_zero_i && j_non_zero_e)
844  sparsity.add (dofs_on_this_cell[i],
845  dofs_on_other_cell[j]);
846  if (i_non_zero_e && j_non_zero_i)
847  sparsity.add (dofs_on_other_cell[i],
848  dofs_on_this_cell[j]);
849  if (i_non_zero_i && j_non_zero_i)
850  sparsity.add (dofs_on_this_cell[i],
851  dofs_on_this_cell[j]);
852  if (i_non_zero_e && j_non_zero_e)
853  sparsity.add (dofs_on_other_cell[i],
854  dofs_on_other_cell[j]);
855  }
856 
857  if (flux_dof_mask(j,i) == DoFTools::always)
858  {
859  sparsity.add (dofs_on_this_cell[j],
860  dofs_on_other_cell[i]);
861  sparsity.add (dofs_on_other_cell[j],
862  dofs_on_this_cell[i]);
863  sparsity.add (dofs_on_this_cell[j],
864  dofs_on_this_cell[i]);
865  sparsity.add (dofs_on_other_cell[j],
866  dofs_on_other_cell[i]);
867  }
868  if (flux_dof_mask(j,i) == DoFTools::nonzero)
869  {
870  if (j_non_zero_i && i_non_zero_e)
871  sparsity.add (dofs_on_this_cell[j],
872  dofs_on_other_cell[i]);
873  if (j_non_zero_e && i_non_zero_i)
874  sparsity.add (dofs_on_other_cell[j],
875  dofs_on_this_cell[i]);
876  if (j_non_zero_i && i_non_zero_i)
877  sparsity.add (dofs_on_this_cell[j],
878  dofs_on_this_cell[i]);
879  if (j_non_zero_e && i_non_zero_e)
880  sparsity.add (dofs_on_other_cell[j],
881  dofs_on_other_cell[i]);
882  }
883  }
884  }
885  neighbor->face(neighbor_face)->set_user_flag ();
886  }
887  }
888  }
889 
890  // finally restore the user flags
891  const_cast<Triangulation<dim,spacedim> &>(dof.get_triangulation()).load_user_flags(user_flags);
892  }
893 
894 
895 
896  template <int dim, typename SparsityPatternType, int spacedim>
897  void
899  SparsityPatternType &sparsity,
900  const unsigned int level,
901  const Table<2,DoFTools::Coupling> &flux_mask)
902  {
903  const FiniteElement<dim> &fe = dof.get_fe();
904  const unsigned int n_comp = fe.n_components();
905  (void)n_comp;
906 
907  Assert ((level>=1) && (level<dof.get_triangulation().n_global_levels()),
908  ExcIndexRange(level, 1, dof.get_triangulation().n_global_levels()));
909 
910  const types::global_dof_index fine_dofs = dof.n_dofs(level);
911  const types::global_dof_index coarse_dofs = dof.n_dofs(level-1);
912  (void)fine_dofs;
913  (void)coarse_dofs;
914 
915  // Matrix maps from fine level to coarse level
916 
917  Assert (sparsity.n_rows() == coarse_dofs,
918  ExcDimensionMismatch (sparsity.n_rows(), coarse_dofs));
919  Assert (sparsity.n_cols() == fine_dofs,
920  ExcDimensionMismatch (sparsity.n_cols(), fine_dofs));
921  Assert (flux_mask.n_rows() == n_comp,
922  ExcDimensionMismatch (flux_mask.n_rows(), n_comp));
923  Assert (flux_mask.n_cols() == n_comp,
924  ExcDimensionMismatch (flux_mask.n_cols(), n_comp));
925 
926  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
927  std::vector<types::global_dof_index> dofs_on_this_cell(dofs_per_cell);
928  std::vector<types::global_dof_index> dofs_on_other_cell(dofs_per_cell);
929  Table<2,bool> support_on_face(dofs_per_cell, GeometryInfo<dim>::faces_per_cell);
930 
931  typename DoFHandler<dim,spacedim>::cell_iterator cell = dof.begin(level),
932  endc = dof.end(level);
933 
934  const Table<2,DoFTools::Coupling> flux_dof_mask
936 
937  for (unsigned int i=0; i<dofs_per_cell; ++i)
938  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
939  support_on_face(i,f) = fe.has_support_on_face(i,f);
940 
941  for (; cell!=endc; ++cell)
942  {
943  if (!cell->is_locally_owned_on_level()) continue;
944 
945  cell->get_mg_dof_indices (dofs_on_this_cell);
946  // Loop over all interior neighbors
947  for (unsigned int face = 0;
948  face < GeometryInfo<dim>::faces_per_cell;
949  ++face)
950  {
951  // Neighbor is coarser
952  bool use_face = false;
953  if ((! cell->at_boundary(face)) &&
954  (static_cast<unsigned int>(cell->neighbor_level(face)) != level))
955  use_face = true;
956  else if (cell->has_periodic_neighbor(face) &&
957  (static_cast<unsigned int>(cell->periodic_neighbor_level(face)) != level))
958  use_face = true;
959 
960  if (use_face)
961  {
963  neighbor = cell->neighbor_or_periodic_neighbor(face);
964  neighbor->get_mg_dof_indices (dofs_on_other_cell);
965 
966  for (unsigned int i=0; i<dofs_per_cell; ++i)
967  {
968  for (unsigned int j=0; j<dofs_per_cell; ++j)
969  {
970  if (flux_dof_mask(i,j) != DoFTools::none)
971  {
972  sparsity.add (dofs_on_other_cell[i],
973  dofs_on_this_cell[j]);
974  sparsity.add (dofs_on_other_cell[j],
975  dofs_on_this_cell[i]);
976  }
977  }
978  }
979  }
980  }
981  }
982  }
983 
984 
985 
986  template <typename DoFHandlerType, typename SparsityPatternType>
987  void
988  make_interface_sparsity_pattern (const DoFHandlerType &dof,
989  const MGConstrainedDoFs &mg_constrained_dofs,
990  SparsityPatternType &sparsity,
991  const unsigned int level)
992  {
993  const types::global_dof_index n_dofs = dof.n_dofs(level);
994  (void)n_dofs;
995 
996  Assert (sparsity.n_rows() == n_dofs,
997  ExcDimensionMismatch (sparsity.n_rows(), n_dofs));
998  Assert (sparsity.n_cols() == n_dofs,
999  ExcDimensionMismatch (sparsity.n_cols(), n_dofs));
1000 
1001  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
1002  std::vector<types::global_dof_index> dofs_on_this_cell(dofs_per_cell);
1003  typename DoFHandlerType::cell_iterator cell = dof.begin(level),
1004  endc = dof.end(level);
1005  for (; cell!=endc; ++cell)
1006  if (cell->is_locally_owned_on_level())
1007  {
1008  cell->get_mg_dof_indices (dofs_on_this_cell);
1009  for (unsigned int i=0; i<dofs_per_cell; ++i)
1010  for (unsigned int j=0; j<dofs_per_cell; ++j)
1011  if (mg_constrained_dofs.is_interface_matrix_entry(level,dofs_on_this_cell[i],dofs_on_this_cell[j]))
1012  sparsity.add (dofs_on_this_cell[i],
1013  dofs_on_this_cell[j]);
1014  }
1015  }
1016 
1017 
1018 
1019  template <int dim, int spacedim>
1020  void
1022  std::vector<std::vector<types::global_dof_index> > &result,
1023  bool only_once,
1024  std::vector<unsigned int> target_component)
1025  {
1026  const FiniteElement<dim> &fe = dof_handler.get_fe();
1027  const unsigned int n_components = fe.n_components();
1028  const unsigned int nlevels = dof_handler.get_triangulation().n_global_levels();
1029 
1030  Assert (result.size() == nlevels,
1031  ExcDimensionMismatch(result.size(), nlevels));
1032 
1033  if (target_component.size() == 0)
1034  {
1035  target_component.resize(n_components);
1036  for (unsigned int i=0; i<n_components; ++i)
1037  target_component[i] = i;
1038  }
1039 
1040  Assert(target_component.size() == n_components,
1041  ExcDimensionMismatch(target_component.size(), n_components));
1042 
1043  for (unsigned int l=0; l<nlevels; ++l)
1044  {
1045  result[l].resize (n_components);
1046  std::fill (result[l].begin(),result[l].end(), 0U);
1047 
1048  // special case for only one
1049  // component. treat this first
1050  // since it does not require any
1051  // computations
1052  if (n_components == 1)
1053  {
1054  result[l][0] = dof_handler.n_dofs(l);
1055  }
1056  else
1057  {
1058  // otherwise determine the number
1059  // of dofs in each component
1060  // separately. do so in parallel
1061  std::vector<std::vector<bool> >
1062  dofs_in_component (n_components,
1063  std::vector<bool>(dof_handler.n_dofs(l),
1064  false));
1065  std::vector<ComponentMask> component_select (n_components);
1066  Threads::TaskGroup<> tasks;
1067  for (unsigned int i=0; i<n_components; ++i)
1068  {
1069  void (*fun_ptr) (const unsigned int level,
1070  const DoFHandler<dim,spacedim> &,
1071  const ComponentMask &,
1072  std::vector<bool> &)
1074 
1075  std::vector<bool> tmp(n_components, false);
1076  tmp[i] = true;
1077  component_select[i] = ComponentMask(tmp);
1078 
1079  tasks += Threads::new_task (fun_ptr,
1080  l, dof_handler,
1081  component_select[i],
1082  dofs_in_component[i]);
1083  }
1084  tasks.join_all();
1085 
1086  // next count what we got
1087  unsigned int component = 0;
1088  for (unsigned int b=0; b<fe.n_base_elements(); ++b)
1089  {
1090  const FiniteElement<dim> &base = fe.base_element(b);
1091  // Dimension of base element
1092  unsigned int d = base.n_components();
1093 
1094  for (unsigned int m=0; m<fe.element_multiplicity(b); ++m)
1095  {
1096  for (unsigned int dd=0; dd<d; ++dd)
1097  {
1098  if (base.is_primitive() || (!only_once || dd==0))
1099  result[l][target_component[component]]
1100  += std::count(dofs_in_component[component].begin(),
1101  dofs_in_component[component].end(),
1102  true);
1103  ++component;
1104  }
1105  }
1106  }
1107  // finally sanity check
1108  Assert (!dof_handler.get_fe().is_primitive()
1109  ||
1110  std::accumulate (result[l].begin(),
1111  result[l].end(),
1113  ==
1114  dof_handler.n_dofs(l),
1115  ExcInternalError());
1116  }
1117  }
1118  }
1119 
1120 
1121 
1122  template <typename DoFHandlerType>
1123  void
1125  (const DoFHandlerType &dof_handler,
1126  std::vector<std::vector<types::global_dof_index> > &dofs_per_block,
1127  std::vector<unsigned int> target_block)
1128  {
1130  const unsigned int n_blocks = fe.n_blocks();
1131  const unsigned int n_levels = dof_handler.get_triangulation().n_global_levels();
1132 
1133  AssertDimension (dofs_per_block.size(), n_levels);
1134 
1135  for (unsigned int l=0; l<n_levels; ++l)
1136  std::fill (dofs_per_block[l].begin(), dofs_per_block[l].end(), 0U);
1137  // If the empty vector was given as
1138  // default argument, set up this
1139  // vector as identity.
1140  if (target_block.size()==0)
1141  {
1142  target_block.resize(n_blocks);
1143  for (unsigned int i=0; i<n_blocks; ++i)
1144  target_block[i] = i;
1145  }
1146  Assert(target_block.size()==n_blocks,
1147  ExcDimensionMismatch(target_block.size(),n_blocks));
1148 
1149  const unsigned int max_block
1150  = *std::max_element (target_block.begin(),
1151  target_block.end());
1152  const unsigned int n_target_blocks = max_block + 1;
1153  (void)n_target_blocks;
1154 
1155  for (unsigned int l=0; l<n_levels; ++l)
1156  AssertDimension (dofs_per_block[l].size(), n_target_blocks);
1157 
1158  // special case for only one
1159  // block. treat this first
1160  // since it does not require any
1161  // computations
1162  if (n_blocks == 1)
1163  {
1164  for (unsigned int l=0; l<n_levels; ++l)
1165  dofs_per_block[l][0] = dof_handler.n_dofs(l);
1166  return;
1167  }
1168  // otherwise determine the number
1169  // of dofs in each block
1170  // separately. do so in parallel
1171  for (unsigned int l=0; l<n_levels; ++l)
1172  {
1173  std::vector<std::vector<bool> >
1174  dofs_in_block (n_blocks, std::vector<bool>(dof_handler.n_dofs(l), false));
1175  std::vector<BlockMask> block_select (n_blocks);
1176  Threads::TaskGroup<> tasks;
1177  for (unsigned int i=0; i<n_blocks; ++i)
1178  {
1179  void (*fun_ptr) (const unsigned int level,
1180  const DoFHandlerType &,
1181  const BlockMask &,
1182  std::vector<bool> &)
1183  = &DoFTools::extract_level_dofs<DoFHandlerType>;
1184 
1185  std::vector<bool> tmp(n_blocks, false);
1186  tmp[i] = true;
1187  block_select[i] = tmp;
1188 
1189  tasks += Threads::new_task (fun_ptr,
1190  l, dof_handler, block_select[i],
1191  dofs_in_block[i]);
1192  }
1193  tasks.join_all ();
1194 
1195  // next count what we got
1196  for (unsigned int block=0; block<fe.n_blocks(); ++block)
1197  dofs_per_block[l][target_block[block]]
1198  += std::count(dofs_in_block[block].begin(),
1199  dofs_in_block[block].end(),
1200  true);
1201  }
1202  }
1203 
1204 
1205 
1206  template <int dim, int spacedim>
1207  void
1209  const DoFHandler<dim,spacedim> &dof,
1210  const typename FunctionMap<dim>::type &function_map,
1211  std::vector<std::set<types::global_dof_index> > &boundary_indices,
1212  const ComponentMask &component_mask)
1213  {
1214  Assert (boundary_indices.size() == dof.get_triangulation().n_global_levels(),
1215  ExcDimensionMismatch (boundary_indices.size(),
1216  dof.get_triangulation().n_global_levels()));
1217 
1218  std::set<types::boundary_id> boundary_ids;
1219  typename std::map<types::boundary_id, const Function<dim>* >::const_iterator it
1220  = function_map.begin();
1221  for (; it!=function_map.end(); ++it)
1222  boundary_ids.insert(it->first);
1223 
1224  std::vector<IndexSet> boundary_indexset;
1225  make_boundary_list(dof, boundary_ids, boundary_indexset, component_mask);
1226  for (unsigned int i=0; i<dof.get_triangulation().n_global_levels(); ++i)
1227  boundary_indices[i].insert(boundary_indexset[i].begin(),
1228  boundary_indexset[i].end());
1229  }
1230 
1231 
1232  template <int dim, int spacedim>
1233  void
1235  const typename FunctionMap<dim>::type &function_map,
1236  std::vector<IndexSet> &boundary_indices,
1237  const ComponentMask &component_mask)
1238  {
1239  Assert (boundary_indices.size() == dof.get_triangulation().n_global_levels(),
1240  ExcDimensionMismatch (boundary_indices.size(),
1241  dof.get_triangulation().n_global_levels()));
1242 
1243  std::set<types::boundary_id> boundary_ids;
1244  typename std::map<types::boundary_id, const Function<dim>* >::const_iterator it = function_map.begin();
1245  for (; it!=function_map.end(); ++it)
1246  boundary_ids.insert(it->first);
1247 
1248  make_boundary_list (dof, boundary_ids, boundary_indices, component_mask);
1249  }
1250 
1251 
1252 
1253  template <int dim, int spacedim>
1254  void
1256  const std::set<types::boundary_id> &boundary_ids,
1257  std::vector<IndexSet> &boundary_indices,
1258  const ComponentMask &component_mask)
1259  {
1260  boundary_indices.resize(dof.get_triangulation().n_global_levels());
1261 
1262  // if for whatever reason we were passed an empty set, return immediately
1263  if (boundary_ids.size() == 0)
1264  return;
1265 
1266  for (unsigned int i=0; i<dof.get_triangulation().n_global_levels(); ++i)
1267  if (boundary_indices[i].size() == 0)
1268  boundary_indices[i] = IndexSet (dof.n_dofs(i));
1269 
1270  const unsigned int n_components = DoFTools::n_components(dof);
1271  const bool fe_is_system = (n_components != 1);
1272 
1273  std::vector<types::global_dof_index> local_dofs;
1274  local_dofs.reserve (DoFTools::max_dofs_per_face(dof));
1275  std::fill (local_dofs.begin (),
1276  local_dofs.end (),
1278 
1279  // First, deal with the simpler case when we have to identify all boundary dofs
1280  if (component_mask.n_selected_components(n_components) == n_components)
1281  {
1283  cell = dof.begin(),
1284  endc = dof.end();
1285  for (; cell!=endc; ++cell)
1286  {
1287  if (dof.get_triangulation().locally_owned_subdomain()!=numbers::invalid_subdomain_id
1288  && cell->level_subdomain_id()==numbers::artificial_subdomain_id)
1289  continue;
1290  const FiniteElement<dim> &fe = cell->get_fe();
1291  const unsigned int level = cell->level();
1292  local_dofs.resize(fe.dofs_per_face);
1293 
1294  for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
1295  ++face_no)
1296  if (cell->at_boundary(face_no) == true)
1297  {
1299  face = cell->face(face_no);
1300  const types::boundary_id bi = face->boundary_id();
1301  // Face is listed in boundary map
1302  if (boundary_ids.find(bi) != boundary_ids.end())
1303  {
1304  face->get_mg_dof_indices(level, local_dofs);
1305  boundary_indices[level].add_indices(local_dofs.begin(), local_dofs.end());
1306  }
1307  }
1308  }
1309  }
1310  else
1311  {
1312  Assert (component_mask.n_selected_components(n_components) > 0,
1313  ExcMessage("It's probably worthwhile to select at least one component."));
1314 
1316  cell = dof.begin(),
1317  endc = dof.end();
1318  for (; cell!=endc; ++cell)
1319  if (dof.get_triangulation().locally_owned_subdomain()==numbers::invalid_subdomain_id
1320  || cell->level_subdomain_id()!=numbers::artificial_subdomain_id)
1321  for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
1322  ++face_no)
1323  {
1324  if (cell->at_boundary(face_no) == false)
1325  continue;
1326 
1327  const FiniteElement<dim> &fe = cell->get_fe();
1328  const unsigned int level = cell->level();
1329 
1330  typename DoFHandler<dim,spacedim>::face_iterator face = cell->face(face_no);
1331  const types::boundary_id boundary_component = face->boundary_id();
1332  if (boundary_ids.find(boundary_component) != boundary_ids.end())
1333  // we want to constrain this boundary
1334  {
1335 
1336  for (unsigned int i=0; i<cell->get_fe().dofs_per_cell; ++i)
1337  {
1338  const ComponentMask &nonzero_component_array
1339  = cell->get_fe().get_nonzero_components (i);
1340  // if we want to constrain one of the nonzero components,
1341  // we have to constrain all of them
1342 
1343  bool selected = false;
1344  for (unsigned int c=0; c<n_components; ++c)
1345  if (nonzero_component_array[c] == true
1346  && component_mask[c]== true)
1347  {
1348  selected = true;
1349  break;
1350  }
1351  if (selected)
1352  for (unsigned int c=0; c<n_components; ++c)
1353  Assert (nonzero_component_array[c] == false || component_mask[c] == true,
1354  ExcMessage ("You are using a non-primitive FiniteElement "
1355  "and try to constrain just some of its components!"));
1356  }
1357 
1358  // get indices, physical location and boundary values of dofs on this face
1359  local_dofs.resize (fe.dofs_per_face);
1360  face->get_mg_dof_indices (level, local_dofs);
1361  if (fe_is_system)
1362  {
1363  for (unsigned int i=0; i<local_dofs.size(); ++i)
1364  {
1365  unsigned int component = numbers::invalid_unsigned_int;
1366  if (fe.is_primitive())
1367  component = fe.face_system_to_component_index(i).first;
1368  else
1369  {
1370  // Just pick the first of the components
1371  // We already know that either all or none
1372  // of the components are selected
1373  const ComponentMask &nonzero_component_array
1374  = cell->get_fe().get_nonzero_components (i);
1375  for (unsigned int c=0; c<n_components; ++c)
1376  if (nonzero_component_array[c] == true)
1377  {
1378  component = c;
1379  break;
1380  }
1381  }
1383  if (component_mask[component] == true)
1384  boundary_indices[level].add_index(local_dofs[i]);
1385  }
1386  }
1387  else
1388  boundary_indices[level].add_indices(local_dofs.begin(), local_dofs.end());
1389  }
1390  }
1391  }
1392  }
1393 
1394 
1395  template <int dim, int spacedim>
1396  void
1397  extract_non_interface_dofs (const DoFHandler<dim,spacedim> &mg_dof_handler,
1398  std::vector<std::set<types::global_dof_index> > &non_interface_dofs)
1399  {
1400  Assert (non_interface_dofs.size() == mg_dof_handler.get_triangulation().n_global_levels(),
1401  ExcDimensionMismatch (non_interface_dofs.size(),
1402  mg_dof_handler.get_triangulation().n_global_levels()));
1403 
1404  const FiniteElement<dim,spacedim> &fe = mg_dof_handler.get_fe();
1405 
1406  const unsigned int dofs_per_cell = fe.dofs_per_cell;
1407  const unsigned int dofs_per_face = fe.dofs_per_face;
1408 
1409  std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
1410  std::vector<bool> cell_dofs(dofs_per_cell, false);
1411  std::vector<bool> cell_dofs_interface(dofs_per_cell, false);
1412 
1413  typename DoFHandler<dim>::cell_iterator cell = mg_dof_handler.begin(),
1414  endc = mg_dof_handler.end();
1415 
1416 
1417  for (; cell!=endc; ++cell)
1418  {
1419  if (mg_dof_handler.get_triangulation().locally_owned_subdomain()!=numbers::invalid_subdomain_id
1420  && cell->level_subdomain_id()!=mg_dof_handler.get_triangulation().locally_owned_subdomain())
1421  continue;
1422 
1423  std::fill (cell_dofs.begin(), cell_dofs.end(), false);
1424  std::fill (cell_dofs_interface.begin(), cell_dofs_interface.end(), false);
1425 
1426  for (unsigned int face_nr=0; face_nr<GeometryInfo<dim>::faces_per_cell; ++face_nr)
1427  {
1428  const typename DoFHandler<dim,spacedim>::face_iterator face = cell->face(face_nr);
1429  if (!face->at_boundary())
1430  {
1431  //interior face
1432  const typename DoFHandler<dim>::cell_iterator
1433  neighbor = cell->neighbor(face_nr);
1434 
1435  if ((neighbor->level() < cell->level()))
1436  {
1437  for (unsigned int j=0; j<dofs_per_face; ++j)
1438  cell_dofs_interface[fe.face_to_cell_index(j,face_nr)] = true;
1439  }
1440  else
1441  {
1442  for (unsigned int j=0; j<dofs_per_face; ++j)
1443  cell_dofs[fe.face_to_cell_index(j,face_nr)] = true;
1444  }
1445  }
1446  else
1447  {
1448  //boundary face
1449  for (unsigned int j=0; j<dofs_per_face; ++j)
1450  cell_dofs[fe.face_to_cell_index(j,face_nr)] = true;
1451  }
1452  }
1453 
1454  const unsigned int level = cell->level();
1455  cell->get_mg_dof_indices (local_dof_indices);
1456 
1457  for (unsigned int i=0; i<dofs_per_cell; ++i)
1458  if (cell_dofs[i] && !cell_dofs_interface[i])
1459  non_interface_dofs[level].insert(local_dof_indices[i]);
1460  }
1461  }
1462 
1463 
1464  template <int dim, int spacedim>
1465  void
1467  std::vector<IndexSet> &interface_dofs)
1468  {
1469  Assert (interface_dofs.size() == mg_dof_handler.get_triangulation().n_global_levels(),
1470  ExcDimensionMismatch (interface_dofs.size(),
1471  mg_dof_handler.get_triangulation().n_global_levels()));
1472 
1473  std::vector<std::vector<types::global_dof_index> >
1474  tmp_interface_dofs(interface_dofs.size());
1475 
1476  const FiniteElement<dim,spacedim> &fe = mg_dof_handler.get_fe();
1477 
1478  const unsigned int dofs_per_cell = fe.dofs_per_cell;
1479  const unsigned int dofs_per_face = fe.dofs_per_face;
1480 
1481  std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
1482 
1483  std::vector<bool> cell_dofs(dofs_per_cell, false);
1484 
1485  typename DoFHandler<dim>::cell_iterator cell = mg_dof_handler.begin(),
1486  endc = mg_dof_handler.end();
1487 
1488  for (; cell!=endc; ++cell)
1489  {
1490  // Do not look at artificial level cells (in a serial computation we
1491  // need to ignore the level_subdomain_id() because it is never set).
1492  if (mg_dof_handler.get_triangulation().locally_owned_subdomain()!=numbers::invalid_subdomain_id
1493  && cell->level_subdomain_id()==numbers::artificial_subdomain_id)
1494  continue;
1495 
1496  bool has_coarser_neighbor = false;
1497 
1498  std::fill (cell_dofs.begin(), cell_dofs.end(), false);
1499 
1500  for (unsigned int face_nr=0; face_nr<GeometryInfo<dim>::faces_per_cell; ++face_nr)
1501  {
1502  const typename DoFHandler<dim,spacedim>::face_iterator face = cell->face(face_nr);
1503  if (!face->at_boundary())
1504  {
1505  //interior face
1506  const typename DoFHandler<dim>::cell_iterator
1507  neighbor = cell->neighbor(face_nr);
1508 
1509  // only process cell pairs if one or both of them are owned by me (ignore if running in serial)
1510  if (mg_dof_handler.get_triangulation().locally_owned_subdomain()!=numbers::invalid_subdomain_id
1511  &&
1512  neighbor->level_subdomain_id()==numbers::artificial_subdomain_id)
1513  continue;
1514 
1515  // Do refinement face from the coarse side
1516  if (neighbor->level() < cell->level())
1517  {
1518  for (unsigned int j=0; j<dofs_per_face; ++j)
1519  cell_dofs[fe.face_to_cell_index(j,face_nr)] = true;
1520 
1521  has_coarser_neighbor = true;
1522  }
1523  }
1524  }
1525 
1526  if (has_coarser_neighbor == false)
1527  continue;
1528 
1529  const unsigned int level = cell->level();
1530  cell->get_mg_dof_indices (local_dof_indices);
1531 
1532  for (unsigned int i=0; i<dofs_per_cell; ++i)
1533  {
1534  if (cell_dofs[i])
1535  tmp_interface_dofs[level].push_back(local_dof_indices[i]);
1536  }
1537  }
1538 
1539  for (unsigned int l=0; l<mg_dof_handler.get_triangulation().n_global_levels(); ++l)
1540  {
1541  interface_dofs[l].clear();
1542  std::sort(tmp_interface_dofs[l].begin(), tmp_interface_dofs[l].end());
1543  interface_dofs[l].add_indices(tmp_interface_dofs[l].begin(),
1544  std::unique(tmp_interface_dofs[l].begin(),
1545  tmp_interface_dofs[l].end()));
1546  interface_dofs[l].compress();
1547  }
1548 
1549  }
1550 
1551 
1552 
1553  template <int dim, int spacedim>
1554  unsigned int
1556  {
1557  // Find minimum level for an active cell in
1558  // this locally owned subdomain
1559  // Note: with the way active cells are traversed,
1560  // the first locally owned cell we find will have
1561  // the lowest level in the particular subdomain.
1562  unsigned int min_level = tria.n_global_levels();
1564  endc = tria.end();
1565  for (; cell!=endc; ++cell)
1566  if (cell->is_locally_owned())
1567  {
1568  min_level = cell->level();
1569  break;
1570  }
1571 
1572  unsigned int global_min = min_level;
1573  // If necessary, communicate to find minimum
1574  // level for an active cell over all subdomains
1576  = dynamic_cast<const parallel::Triangulation<dim,spacedim> *>
1577  (&tria))
1578  global_min = Utilities::MPI::min(min_level, tr->get_communicator());
1579 
1580  AssertIndexRange(global_min, tria.n_global_levels());
1581 
1582  return global_min;
1583  }
1584 }
1585 
1586 
1587 // explicit instantiations
1588 #include "mg_tools.inst"
1589 
1590 DEAL_II_NAMESPACE_CLOSE
const unsigned int first_hex_index
Definition: fe_base.h:271
static const unsigned int invalid_unsigned_int
Definition: types.h:173
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
const types::subdomain_id invalid_subdomain_id
Definition: types.h:248
void clear_user_flags()
Definition: tria.cc:9729
cell_iterator begin(const unsigned int level=0) const
Definition: dof_handler.cc:723
Task< RT > new_task(const std::function< RT()> &function)
void load_user_flags(std::istream &in)
Definition: tria.cc:9786
unsigned int boundary_id
Definition: types.h:110
cell_iterator end() const
Definition: dof_handler.cc:751
void make_flux_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:573
#define AssertIndexRange(index, range)
Definition: exceptions.h:1284
void make_sparsity_pattern(const DoFHandlerType &dof_handler, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:540
ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:229
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: tria.cc:10508
bool is_primitive() const
Definition: fe.h:3228
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
Table< 2, Coupling > dof_couplings_from_component_couplings(const FiniteElement< dim, spacedim > &fe, const Table< 2, Coupling > &component_couplings)
unsigned int n_blocks() const
bool is_interface_matrix_entry(const unsigned int level, const types::global_dof_index i, const types::global_dof_index j) const
ActiveSelector::face_iterator face_iterator
Definition: dof_handler.h:275
cell_iterator end() const
Definition: tria.cc:10576
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: dof_handler.cc:735
void make_boundary_list(const DoFHandler< dim, spacedim > &mg_dof, const typename FunctionMap< dim >::type &function_map, std::vector< std::set< types::global_dof_index > > &boundary_indices, const ComponentMask &component_mask=ComponentMask())
Definition: mg_tools.cc:1208
void make_interface_sparsity_pattern(const DoFHandlerType &dof_handler, const MGConstrainedDoFs &mg_constrained_dofs, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:988
void count_dofs_per_component(const DoFHandler< dim, spacedim > &mg_dof, std::vector< std::vector< types::global_dof_index > > &result, const bool only_once=false, std::vector< unsigned int > target_component=std::vector< unsigned int >())
Definition: mg_tools.cc:1021
static ::ExceptionBase & ExcMessage(std::string arg1)
unsigned int max_dofs_per_face(const DoFHandler< dim, spacedim > &dh)
ActiveSelector::cell_iterator cell_iterator
Definition: dof_handler.h:257
const unsigned int first_quad_index
Definition: fe_base.h:266
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:1142
unsigned int element_multiplicity(const unsigned int index) const
Definition: fe.h:3056
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
const FiniteElement< dim, spacedim > & get_fe(const unsigned int index=0) const
std::pair< unsigned int, unsigned int > face_system_to_component_index(const unsigned int index) const
Definition: fe.h:3088
types::global_dof_index n_dofs() const
virtual const FiniteElement< dim, spacedim > & base_element(const unsigned int index) const
Definition: fe.cc:1242
std::map< types::boundary_id, const Function< dim, Number > * > type
Definition: function_map.h:81
virtual unsigned int face_to_cell_index(const unsigned int face_dof_index, const unsigned int face, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false) const
Definition: fe.cc:525
const unsigned int dofs_per_cell
Definition: fe_base.h:295
types::global_dof_index first_block_of_base(const unsigned int b) const
Definition: fe.h:3143
void convert_couplings_to_blocks(const hp::DoFHandler< dim, spacedim > &dof_handler, const Table< 2, Coupling > &table_by_component, std::vector< Table< 2, Coupling > > &tables_by_block)
Definition: dof_tools.cc:2227
const types::subdomain_id artificial_subdomain_id
Definition: types.h:264
void compute_row_length_vector(const DoFHandler< dim, spacedim > &dofs, const unsigned int level, std::vector< unsigned int > &row_lengths, const DoFTools::Coupling flux_couplings=DoFTools::none)
Definition: mg_tools.cc:107
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
Definition: fe.h:3032
unsigned int n_components() const
std::pair< unsigned int, types::global_dof_index > system_to_block_index(const unsigned int component) const
Definition: fe.h:3176
virtual unsigned int n_global_levels() const
T min(const T &t, const MPI_Comm &mpi_communicator)
unsigned int n_selected_components(const unsigned int overall_number_of_components=numbers::invalid_unsigned_int) const
const unsigned int dofs_per_face
Definition: fe_base.h:288
const unsigned int first_line_index
Definition: fe_base.h:261
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:1125
void extract_inner_interface_dofs(const DoFHandler< dim, spacedim > &mg_dof_handler, std::vector< IndexSet > &interface_dofs)
Definition: mg_tools.cc:1466
void save_user_flags(std::ostream &out) const
Definition: tria.cc:9739
static ::ExceptionBase & ExcNotImplemented()
const Triangulation< dim, spacedim > & get_triangulation() const
Definition: table.h:34
void extract_level_dofs(const unsigned int level, const DoFHandlerType &dof, const ComponentMask &component_mask, std::vector< bool > &selected_dofs)
Definition: dof_tools.cc:507
void make_flux_sparsity_pattern_edge(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:648
const types::global_dof_index invalid_dof_index
Definition: types.h:187
unsigned int n_base_elements() const
Definition: fe.h:3046
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
unsigned int max_level_for_coarse_mesh(const Triangulation< dim, spacedim > &tria)
Definition: mg_tools.cc:1555
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
Definition: fe.cc:1088
static ::ExceptionBase & ExcInternalError()