Reference documentation for deal.II version 9.1.0-pre
dof_renumbering.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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/quadrature_lib.h>
17 #include <deal.II/base/template_constraints.h>
18 #include <deal.II/base/thread_management.h>
19 #include <deal.II/base/types.h>
20 #include <deal.II/base/utilities.h>
21 
22 #include <deal.II/distributed/tria.h>
23 
24 #include <deal.II/dofs/dof_accessor.h>
25 #include <deal.II/dofs/dof_handler.h>
26 #include <deal.II/dofs/dof_renumbering.h>
27 #include <deal.II/dofs/dof_tools.h>
28 
29 #include <deal.II/fe/fe.h>
30 
31 #include <deal.II/grid/tria.h>
32 #include <deal.II/grid/tria_iterator.h>
33 
34 #include <deal.II/hp/dof_handler.h>
35 #include <deal.II/hp/fe_collection.h>
36 #include <deal.II/hp/fe_values.h>
37 
38 #include <deal.II/lac/affine_constraints.h>
39 #include <deal.II/lac/dynamic_sparsity_pattern.h>
40 #include <deal.II/lac/sparsity_pattern.h>
41 #include <deal.II/lac/sparsity_tools.h>
42 
43 #include <deal.II/multigrid/mg_tools.h>
44 
45 #include <boost/config.hpp>
46 #include <boost/graph/adjacency_list.hpp>
47 #include <boost/graph/bandwidth.hpp>
48 #include <boost/graph/cuthill_mckee_ordering.hpp>
49 #include <boost/graph/king_ordering.hpp>
50 #include <boost/graph/minimum_degree_ordering.hpp>
51 #include <boost/graph/properties.hpp>
52 #include <boost/random.hpp>
53 #include <boost/random/uniform_int_distribution.hpp>
54 
55 #include <algorithm>
56 #include <cmath>
57 #include <functional>
58 #include <map>
59 #include <vector>
60 
61 
62 DEAL_II_NAMESPACE_OPEN
63 
64 namespace DoFRenumbering
65 {
66  namespace boost
67  {
68  namespace boosttypes
69  {
70  using namespace ::boost;
71  using namespace std;
72 
73  using Graph = adjacency_list<vecS,
74  vecS,
75  undirectedS,
76  property<vertex_color_t,
77  default_color_type,
78  property<vertex_degree_t, int>>>;
79  using Vertex = graph_traits<Graph>::vertex_descriptor;
80  using size_type = graph_traits<Graph>::vertices_size_type;
81 
82  using Pair = std::pair<size_type, size_type>;
83  } // namespace boosttypes
84 
85 
86  namespace internal
87  {
88  template <typename DoFHandlerType>
89  void
90  create_graph(const DoFHandlerType &dof_handler,
91  const bool use_constraints,
92  boosttypes::Graph & graph,
93  boosttypes::property_map<boosttypes::Graph,
94  boosttypes::vertex_degree_t>::type
95  &graph_degree)
96  {
97  {
98  // create intermediate sparsity pattern (faster than directly
99  // submitting indices)
100  AffineConstraints<double> constraints;
101  if (use_constraints)
102  DoFTools::make_hanging_node_constraints(dof_handler, constraints);
103  constraints.close();
104  DynamicSparsityPattern dsp(dof_handler.n_dofs(),
105  dof_handler.n_dofs());
106  DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints);
107 
108  // submit the entries to the boost graph
109  for (unsigned int row = 0; row < dsp.n_rows(); ++row)
110  for (unsigned int col = 0; col < dsp.row_length(row); ++col)
111  add_edge(row, dsp.column_number(row, col), graph);
112  }
113 
114  boosttypes::graph_traits<boosttypes::Graph>::vertex_iterator ui, ui_end;
115 
116  graph_degree = get(::boost::vertex_degree, graph);
117  for (::boost::tie(ui, ui_end) = vertices(graph); ui != ui_end; ++ui)
118  graph_degree[*ui] = degree(*ui, graph);
119  }
120  } // namespace internal
121 
122 
123  template <typename DoFHandlerType>
124  void
125  Cuthill_McKee(DoFHandlerType &dof_handler,
126  const bool reversed_numbering,
127  const bool use_constraints)
128  {
129  std::vector<types::global_dof_index> renumbering(
130  dof_handler.n_dofs(), numbers::invalid_dof_index);
131  compute_Cuthill_McKee(renumbering,
132  dof_handler,
133  reversed_numbering,
134  use_constraints);
135 
136  // actually perform renumbering;
137  // this is dimension specific and
138  // thus needs an own function
139  dof_handler.renumber_dofs(renumbering);
140  }
141 
142 
143  template <typename DoFHandlerType>
144  void
145  compute_Cuthill_McKee(std::vector<types::global_dof_index> &new_dof_indices,
146  const DoFHandlerType & dof_handler,
147  const bool reversed_numbering,
148  const bool use_constraints)
149  {
150  boosttypes::Graph graph(dof_handler.n_dofs());
151  boosttypes::property_map<boosttypes::Graph,
152  boosttypes::vertex_degree_t>::type graph_degree;
153 
154  internal::create_graph(dof_handler, use_constraints, graph, graph_degree);
155 
156  boosttypes::property_map<boosttypes::Graph,
157  boosttypes::vertex_index_t>::type index_map =
158  get(::boost::vertex_index, graph);
159 
160 
161  std::vector<boosttypes::Vertex> inv_perm(num_vertices(graph));
162 
163  if (reversed_numbering == false)
164  ::boost::cuthill_mckee_ordering(graph,
165  inv_perm.rbegin(),
166  get(::boost::vertex_color, graph),
167  make_degree_map(graph));
168  else
169  ::boost::cuthill_mckee_ordering(graph,
170  inv_perm.begin(),
171  get(::boost::vertex_color, graph),
172  make_degree_map(graph));
173 
174  for (boosttypes::size_type c = 0; c != inv_perm.size(); ++c)
175  new_dof_indices[index_map[inv_perm[c]]] = c;
176 
177  Assert(std::find(new_dof_indices.begin(),
178  new_dof_indices.end(),
179  numbers::invalid_dof_index) == new_dof_indices.end(),
180  ExcInternalError());
181  }
182 
183 
184 
185  template <typename DoFHandlerType>
186  void
187  king_ordering(DoFHandlerType &dof_handler,
188  const bool reversed_numbering,
189  const bool use_constraints)
190  {
191  std::vector<types::global_dof_index> renumbering(
192  dof_handler.n_dofs(), numbers::invalid_dof_index);
193  compute_king_ordering(renumbering,
194  dof_handler,
195  reversed_numbering,
196  use_constraints);
197 
198  // actually perform renumbering;
199  // this is dimension specific and
200  // thus needs an own function
201  dof_handler.renumber_dofs(renumbering);
202  }
203 
204 
205  template <typename DoFHandlerType>
206  void
207  compute_king_ordering(std::vector<types::global_dof_index> &new_dof_indices,
208  const DoFHandlerType & dof_handler,
209  const bool reversed_numbering,
210  const bool use_constraints)
211  {
212  boosttypes::Graph graph(dof_handler.n_dofs());
213  boosttypes::property_map<boosttypes::Graph,
214  boosttypes::vertex_degree_t>::type graph_degree;
215 
216  internal::create_graph(dof_handler, use_constraints, graph, graph_degree);
217 
218  boosttypes::property_map<boosttypes::Graph,
219  boosttypes::vertex_index_t>::type index_map =
220  get(::boost::vertex_index, graph);
221 
222 
223  std::vector<boosttypes::Vertex> inv_perm(num_vertices(graph));
224 
225  if (reversed_numbering == false)
226  ::boost::king_ordering(graph, inv_perm.rbegin());
227  else
228  ::boost::king_ordering(graph, inv_perm.begin());
229 
230  for (boosttypes::size_type c = 0; c != inv_perm.size(); ++c)
231  new_dof_indices[index_map[inv_perm[c]]] = c;
232 
233  Assert(std::find(new_dof_indices.begin(),
234  new_dof_indices.end(),
235  numbers::invalid_dof_index) == new_dof_indices.end(),
236  ExcInternalError());
237  }
238 
239 
240 
241  template <typename DoFHandlerType>
242  void
243  minimum_degree(DoFHandlerType &dof_handler,
244  const bool reversed_numbering,
245  const bool use_constraints)
246  {
247  std::vector<types::global_dof_index> renumbering(
248  dof_handler.n_dofs(), numbers::invalid_dof_index);
249  compute_minimum_degree(renumbering,
250  dof_handler,
251  reversed_numbering,
252  use_constraints);
253 
254  // actually perform renumbering;
255  // this is dimension specific and
256  // thus needs an own function
257  dof_handler.renumber_dofs(renumbering);
258  }
259 
260 
261  template <typename DoFHandlerType>
262  void
264  std::vector<types::global_dof_index> &new_dof_indices,
265  const DoFHandlerType & dof_handler,
266  const bool reversed_numbering,
267  const bool use_constraints)
268  {
269  (void)use_constraints;
270  Assert(use_constraints == false, ExcNotImplemented());
271 
272  // the following code is pretty
273  // much a verbatim copy of the
274  // sample code for the
275  // minimum_degree_ordering manual
276  // page from the BOOST Graph
277  // Library
278  using namespace ::boost;
279 
280  int delta = 0;
281 
282  // must be BGL directed graph now
283  using Graph = adjacency_list<vecS, vecS, directedS>;
284 
285  int n = dof_handler.n_dofs();
286 
287  Graph G(n);
288 
289  std::vector<::types::global_dof_index> dofs_on_this_cell;
290 
291  typename DoFHandlerType::active_cell_iterator cell = dof_handler
292  .begin_active(),
293  endc = dof_handler.end();
294 
295  for (; cell != endc; ++cell)
296  {
297  const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
298 
299  dofs_on_this_cell.resize(dofs_per_cell);
300 
301  cell->get_active_or_mg_dof_indices(dofs_on_this_cell);
302  for (unsigned int i = 0; i < dofs_per_cell; ++i)
303  for (unsigned int j = 0; j < dofs_per_cell; ++j)
304  if (dofs_on_this_cell[i] > dofs_on_this_cell[j])
305  {
306  add_edge(dofs_on_this_cell[i], dofs_on_this_cell[j], G);
307  add_edge(dofs_on_this_cell[j], dofs_on_this_cell[i], G);
308  }
309  }
310 
311 
312  using Vector = std::vector<int>;
313 
314 
315  Vector inverse_perm(n, 0);
316 
317  Vector perm(n, 0);
318 
319 
320  Vector supernode_sizes(n, 1);
321  // init has to be 1
322 
323  ::boost::property_map<Graph, vertex_index_t>::type id =
324  get(vertex_index, G);
325 
326 
327  Vector degree(n, 0);
328 
329 
330  minimum_degree_ordering(
331  G,
332  make_iterator_property_map(degree.begin(), id, degree[0]),
333  inverse_perm.data(),
334  perm.data(),
335  make_iterator_property_map(supernode_sizes.begin(),
336  id,
337  supernode_sizes[0]),
338  delta,
339  id);
340 
341 
342  for (int i = 0; i < n; ++i)
343  {
344  Assert(std::find(perm.begin(), perm.end(), i) != perm.end(),
345  ExcInternalError());
346  Assert(std::find(inverse_perm.begin(), inverse_perm.end(), i) !=
347  inverse_perm.end(),
348  ExcInternalError());
349  Assert(inverse_perm[perm[i]] == i, ExcInternalError());
350  }
351 
352  if (reversed_numbering == true)
353  std::copy(perm.begin(), perm.end(), new_dof_indices.begin());
354  else
355  std::copy(inverse_perm.begin(),
356  inverse_perm.end(),
357  new_dof_indices.begin());
358  }
359 
360  } // namespace boost
361 
362 
363 
364  template <typename DoFHandlerType>
365  void
366  Cuthill_McKee(DoFHandlerType & dof_handler,
367  const bool reversed_numbering,
368  const bool use_constraints,
369  const std::vector<types::global_dof_index> &starting_indices)
370  {
371  std::vector<types::global_dof_index> renumbering(
372  dof_handler.locally_owned_dofs().n_elements(),
374  compute_Cuthill_McKee(renumbering,
375  dof_handler,
376  reversed_numbering,
377  use_constraints,
378  starting_indices);
379 
380  // actually perform renumbering;
381  // this is dimension specific and
382  // thus needs an own function
383  dof_handler.renumber_dofs(renumbering);
384  }
385 
386 
387 
388  template <typename DoFHandlerType>
389  void
391  std::vector<types::global_dof_index> & new_indices,
392  const DoFHandlerType & dof_handler,
393  const bool reversed_numbering,
394  const bool use_constraints,
395  const std::vector<types::global_dof_index> &starting_indices)
396  {
397  // see if there is anything to do at all or whether we can skip the work on
398  // this processor
399  if (dof_handler.locally_owned_dofs().n_elements() == 0)
400  {
401  Assert(new_indices.size() == 0, ExcInternalError());
402  return;
403  }
404 
405  // make the connection graph
406  //
407  // note that if constraints are not requested, then the 'constraints'
408  // object will be empty and using it has no effect
409  IndexSet locally_relevant_dofs;
410  DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
411 
412  AffineConstraints<double> constraints;
413  if (use_constraints)
414  {
415  constraints.reinit(locally_relevant_dofs);
416  DoFTools::make_hanging_node_constraints(dof_handler, constraints);
417  }
418  constraints.close();
419 
420  const IndexSet &locally_owned_dofs = dof_handler.locally_owned_dofs();
421 
422  // see if we can get away with the sequential algorithm
423  if (locally_owned_dofs.n_elements() == locally_owned_dofs.size())
424  {
425  AssertDimension(new_indices.size(), dof_handler.n_dofs());
426 
427  DynamicSparsityPattern dsp(dof_handler.n_dofs(), dof_handler.n_dofs());
428  DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints);
429 
431  new_indices,
432  starting_indices);
433  if (reversed_numbering)
434  new_indices = Utilities::reverse_permutation(new_indices);
435  }
436  else
437  {
438  // we are in the parallel case where we need to work in the
439  // local index space, i.e., the locally owned part of the
440  // sparsity pattern.
441  //
442  // first figure out whether the user only gave us starting
443  // indices that are locally owned, or that are only locally
444  // relevant. in the process, also check that all indices
445  // really belong to at least the locally relevant ones
446  IndexSet locally_active_dofs;
447  DoFTools::extract_locally_active_dofs(dof_handler, locally_active_dofs);
448 
449  bool needs_locally_active = false;
450  for (unsigned int i = 0; i < starting_indices.size(); ++i)
451  {
452  if ((needs_locally_active ==
453  /* previously already set to */ true) ||
454  (locally_owned_dofs.is_element(starting_indices[i]) == false))
455  {
456  Assert(
457  locally_active_dofs.is_element(starting_indices[i]),
458  ExcMessage(
459  "You specified global degree of freedom " +
460  Utilities::to_string(starting_indices[i]) +
461  " as a starting index, but this index is not among the "
462  "locally active ones on this processor, as required "
463  "for this function."));
464  needs_locally_active = true;
465  }
466  }
467 
468  const IndexSet index_set_to_use =
469  (needs_locally_active ? locally_active_dofs : locally_owned_dofs);
470 
471  // then create first the global sparsity pattern, and then the local
472  // sparsity pattern from the global one by transferring its indices to
473  // processor-local (locally owned or locally active) index space
474  DynamicSparsityPattern dsp(dof_handler.n_dofs(),
475  dof_handler.n_dofs(),
476  index_set_to_use);
477  DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints);
478 
479  DynamicSparsityPattern local_sparsity(index_set_to_use.n_elements(),
480  index_set_to_use.n_elements());
481  std::vector<types::global_dof_index> row_entries;
482  for (unsigned int i = 0; i < index_set_to_use.n_elements(); ++i)
483  {
484  const types::global_dof_index row =
485  index_set_to_use.nth_index_in_set(i);
486  const unsigned int row_length = dsp.row_length(row);
487  row_entries.clear();
488  for (unsigned int j = 0; j < row_length; ++j)
489  {
490  const unsigned int col = dsp.column_number(row, j);
491  if (col != row && index_set_to_use.is_element(col))
492  row_entries.push_back(index_set_to_use.index_within_set(col));
493  }
494  local_sparsity.add_entries(i,
495  row_entries.begin(),
496  row_entries.end(),
497  true);
498  }
499 
500  // translate starting indices from global to local indices
501  std::vector<types::global_dof_index> local_starting_indices(
502  starting_indices.size());
503  for (unsigned int i = 0; i < starting_indices.size(); ++i)
504  local_starting_indices[i] =
505  index_set_to_use.index_within_set(starting_indices[i]);
506 
507  // then do the renumbering on the locally owned portion
508  AssertDimension(new_indices.size(), locally_owned_dofs.n_elements());
509  std::vector<types::global_dof_index> my_new_indices(
510  index_set_to_use.n_elements());
512  my_new_indices,
513  local_starting_indices);
514  if (reversed_numbering)
515  my_new_indices = Utilities::reverse_permutation(my_new_indices);
516 
517  // now that we have a re-enumeration of all DoFs, we need to throw
518  // out the ones that are not locally owned in case we have worked
519  // with the locally active ones. that's because the renumbering
520  // functions only want new indices for the locally owned DoFs (other
521  // processors are responsible for renumbering the ones that are
522  // on cell interfaces)
523  if (needs_locally_active == true)
524  {
525  // first step: figure out which DoF indices to eliminate
526  IndexSet active_but_not_owned_dofs = locally_active_dofs;
527  active_but_not_owned_dofs.subtract_set(locally_owned_dofs);
528 
529  std::set<types::global_dof_index> erase_these_indices;
530  for (const auto p : active_but_not_owned_dofs)
531  {
532  const auto index = index_set_to_use.index_within_set(p);
533  Assert(index < index_set_to_use.n_elements(),
534  ExcInternalError());
535  erase_these_indices.insert(my_new_indices[index]);
536  my_new_indices[index] = numbers::invalid_dof_index;
537  }
538  Assert(erase_these_indices.size() ==
539  active_but_not_owned_dofs.n_elements(),
540  ExcInternalError());
541  Assert(static_cast<unsigned int>(
542  std::count(my_new_indices.begin(),
543  my_new_indices.end(),
545  active_but_not_owned_dofs.n_elements(),
546  ExcInternalError());
547 
548  // then compute a renumbering of the remaining ones
549  std::vector<types::global_dof_index> translate_indices(
550  my_new_indices.size());
551  {
552  std::set<types::global_dof_index>::const_iterator
553  next_erased_index = erase_these_indices.begin();
554  types::global_dof_index next_new_index = 0;
555  for (unsigned int i = 0; i < translate_indices.size(); ++i)
556  if ((next_erased_index != erase_these_indices.end()) &&
557  (*next_erased_index == i))
558  {
559  translate_indices[i] = numbers::invalid_dof_index;
560  ++next_erased_index;
561  }
562  else
563  {
564  translate_indices[i] = next_new_index;
565  ++next_new_index;
566  }
567  Assert(next_new_index == locally_owned_dofs.n_elements(),
568  ExcInternalError());
569  }
570 
571  // and then do the renumbering of the result of the
572  // Cuthill-McKee algorithm above, right into the output array
573  new_indices.clear();
574  new_indices.reserve(locally_owned_dofs.n_elements());
575  for (const auto &p : my_new_indices)
577  {
578  Assert(translate_indices[p] != numbers::invalid_dof_index,
579  ExcInternalError());
580  new_indices.push_back(translate_indices[p]);
581  }
582  Assert(new_indices.size() == locally_owned_dofs.n_elements(),
583  ExcInternalError());
584  }
585  else
586  new_indices = std::move(my_new_indices);
587 
588  // convert indices back to global index space. in both of the branches
589  // above, we ended up with new_indices only containing the local
590  // indices of the locally-owned DoFs. so that's where we get the
591  // indices
592  for (std::size_t i = 0; i < new_indices.size(); ++i)
593  new_indices[i] = locally_owned_dofs.nth_index_in_set(new_indices[i]);
594  }
595  }
596 
597 
598 
599  template <typename DoFHandlerType>
600  void
601  Cuthill_McKee(DoFHandlerType & dof_handler,
602  const unsigned int level,
603  const bool reversed_numbering,
604  const std::vector<types::global_dof_index> &starting_indices)
605  {
606  Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index,
608 
609  // make the connection graph
610  DynamicSparsityPattern dsp(dof_handler.n_dofs(level),
611  dof_handler.n_dofs(level));
612  MGTools::make_sparsity_pattern(dof_handler, dsp, level);
613 
614  std::vector<types::global_dof_index> new_indices(dsp.n_rows());
615  SparsityTools::reorder_Cuthill_McKee(dsp, new_indices, starting_indices);
616 
617  if (reversed_numbering)
618  new_indices = Utilities::reverse_permutation(new_indices);
619 
620  // actually perform renumbering;
621  // this is dimension specific and
622  // thus needs an own function
623  dof_handler.renumber_dofs(level, new_indices);
624  }
625 
626 
627 
628  template <typename DoFHandlerType>
629  void
630  component_wise(DoFHandlerType & dof_handler,
631  const std::vector<unsigned int> &component_order_arg)
632  {
633  std::vector<types::global_dof_index> renumbering(
634  dof_handler.n_locally_owned_dofs(), numbers::invalid_dof_index);
635 
636  typename DoFHandlerType::active_cell_iterator start =
637  dof_handler.begin_active();
638  const typename DoFHandlerType::level_cell_iterator end = dof_handler.end();
639 
640  const types::global_dof_index result =
641  compute_component_wise<DoFHandlerType::dimension,
642  DoFHandlerType::space_dimension>(
643  renumbering, start, end, component_order_arg, false);
644  if (result == 0)
645  return;
646 
647  // verify that the last numbered
648  // degree of freedom is either
649  // equal to the number of degrees
650  // of freedom in total (the
651  // sequential case) or in the
652  // distributed case at least
653  // makes sense
654  Assert((result == dof_handler.n_locally_owned_dofs()) ||
655  ((dof_handler.n_locally_owned_dofs() < dof_handler.n_dofs()) &&
656  (result <= dof_handler.n_dofs())),
657  ExcInternalError());
658 
659  dof_handler.renumber_dofs(renumbering);
660  }
661 
662 
663 
664  template <typename DoFHandlerType>
665  void
666  component_wise(DoFHandlerType & dof_handler,
667  const unsigned int level,
668  const std::vector<unsigned int> &component_order_arg)
669  {
670  Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index,
672 
673  std::vector<types::global_dof_index> renumbering(
674  dof_handler.n_dofs(level), numbers::invalid_dof_index);
675 
676  typename DoFHandlerType::level_cell_iterator start =
677  dof_handler.begin(level);
678  typename DoFHandlerType::level_cell_iterator end = dof_handler.end(level);
679 
680  const types::global_dof_index result =
681  compute_component_wise<DoFHandlerType::dimension,
682  DoFHandlerType::space_dimension>(
683  renumbering, start, end, component_order_arg, true);
684 
685  if (result == 0)
686  return;
687 
688  Assert(result == dof_handler.n_dofs(level), ExcInternalError());
689 
690  if (renumbering.size() != 0)
691  dof_handler.renumber_dofs(level, renumbering);
692  }
693 
694 
695 
696  template <int dim, int spacedim, typename CellIterator>
698  compute_component_wise(std::vector<types::global_dof_index> &new_indices,
699  const CellIterator & start,
700  const typename identity<CellIterator>::type &end,
701  const std::vector<unsigned int> &component_order_arg,
702  const bool is_level_operation)
703  {
704  const hp::FECollection<dim, spacedim> fe_collection(
705  start->get_dof_handler().get_fe_collection());
706 
707  // do nothing if the FE has only
708  // one component
709  if (fe_collection.n_components() == 1)
710  {
711  new_indices.resize(0);
712  return 0;
713  }
714 
715  // Copy last argument into a
716  // writable vector.
717  std::vector<unsigned int> component_order(component_order_arg);
718  // If the last argument was an
719  // empty vector, set up things to
720  // store components in the order
721  // found in the system.
722  if (component_order.size() == 0)
723  for (unsigned int i = 0; i < fe_collection.n_components(); ++i)
724  component_order.push_back(i);
725 
726  Assert(component_order.size() == fe_collection.n_components(),
727  ExcDimensionMismatch(component_order.size(),
728  fe_collection.n_components()));
729 
730  for (unsigned int i = 0; i < component_order.size(); ++i)
731  Assert(component_order[i] < fe_collection.n_components(),
732  ExcIndexRange(component_order[i],
733  0,
734  fe_collection.n_components()));
735 
736  // vector to hold the dof indices on
737  // the cell we visit at a time
738  std::vector<types::global_dof_index> local_dof_indices;
739 
740  // prebuilt list to which component
741  // a given dof on a cell
742  // should go. note that we get into
743  // trouble here if the shape
744  // function is not primitive, since
745  // then there is no single vector
746  // component to which it
747  // belongs. in this case, assign it
748  // to the first vector component to
749  // which it belongs
750  std::vector<std::vector<unsigned int>> component_list(fe_collection.size());
751  for (unsigned int f = 0; f < fe_collection.size(); ++f)
752  {
753  const FiniteElement<dim, spacedim> &fe = fe_collection[f];
754  const unsigned int dofs_per_cell = fe.dofs_per_cell;
755  component_list[f].resize(dofs_per_cell);
756  for (unsigned int i = 0; i < dofs_per_cell; ++i)
757  if (fe.is_primitive(i))
758  component_list[f][i] =
759  component_order[fe.system_to_component_index(i).first];
760  else
761  {
762  const unsigned int comp =
764 
765  // then associate this degree
766  // of freedom with this
767  // component
768  component_list[f][i] = component_order[comp];
769  }
770  }
771 
772  // set up a map where for each
773  // component the respective degrees
774  // of freedom are collected.
775  //
776  // note that this map is sorted by
777  // component but that within each
778  // component it is NOT sorted by
779  // dof index. note also that some
780  // dof indices are entered
781  // multiply, so we will have to
782  // take care of that
783  std::vector<std::vector<types::global_dof_index>> component_to_dof_map(
784  fe_collection.n_components());
785  for (CellIterator cell = start; cell != end; ++cell)
786  {
787  if (is_level_operation)
788  {
789  // we are dealing with mg dofs, skip foreign level cells:
790  if (!cell->is_locally_owned_on_level())
791  continue;
792  }
793  else
794  {
795  // we are dealing with active dofs, skip the loop if not locally
796  // owned:
797  if (!cell->is_locally_owned())
798  continue;
799  }
800  // on each cell: get dof indices
801  // and insert them into the global
802  // list using their component
803  const unsigned int fe_index = cell->active_fe_index();
804  const unsigned int dofs_per_cell =
805  fe_collection[fe_index].dofs_per_cell;
806  local_dof_indices.resize(dofs_per_cell);
807  cell->get_active_or_mg_dof_indices(local_dof_indices);
808  for (unsigned int i = 0; i < dofs_per_cell; ++i)
809  if (start->get_dof_handler().locally_owned_dofs().is_element(
810  local_dof_indices[i]))
811  component_to_dof_map[component_list[fe_index][i]].push_back(
812  local_dof_indices[i]);
813  }
814 
815  // now we've got all indices sorted
816  // into buckets labeled by their
817  // target component number. we've
818  // only got to traverse this list
819  // and assign the new indices
820  //
821  // however, we first want to sort
822  // the indices entered into the
823  // buckets to preserve the order
824  // within each component and during
825  // this also remove duplicate
826  // entries
827  //
828  // note that we no longer have to
829  // care about non-primitive shape
830  // functions since the buckets
831  // corresponding to the second and
832  // following vector components of a
833  // non-primitive FE will simply be
834  // empty, everything being shoved
835  // into the first one. The same
836  // holds if several components were
837  // joined into a single target.
838  for (unsigned int component = 0; component < fe_collection.n_components();
839  ++component)
840  {
841  std::sort(component_to_dof_map[component].begin(),
842  component_to_dof_map[component].end());
843  component_to_dof_map[component].erase(
844  std::unique(component_to_dof_map[component].begin(),
845  component_to_dof_map[component].end()),
846  component_to_dof_map[component].end());
847  }
848 
849  // calculate the number of locally owned
850  // DoFs per bucket
851  const unsigned int n_buckets = fe_collection.n_components();
852  std::vector<types::global_dof_index> shifts(n_buckets);
853 
855  (dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
856  &start->get_dof_handler().get_triangulation())))
857  {
858 #ifdef DEAL_II_WITH_MPI
859  std::vector<types::global_dof_index> local_dof_count(n_buckets);
860 
861  for (unsigned int c = 0; c < n_buckets; ++c)
862  local_dof_count[c] = component_to_dof_map[c].size();
863 
864 
865  // gather information from all CPUs
866  std::vector<types::global_dof_index> all_dof_counts(
867  fe_collection.n_components() *
868  Utilities::MPI::n_mpi_processes(tria->get_communicator()));
869 
870  const int ierr = MPI_Allgather(local_dof_count.data(),
871  n_buckets,
872  DEAL_II_DOF_INDEX_MPI_TYPE,
873  all_dof_counts.data(),
874  n_buckets,
875  DEAL_II_DOF_INDEX_MPI_TYPE,
876  tria->get_communicator());
877  AssertThrowMPI(ierr);
878 
879  for (unsigned int i = 0; i < n_buckets; ++i)
880  Assert(
881  all_dof_counts[n_buckets * tria->locally_owned_subdomain() + i] ==
882  local_dof_count[i],
883  ExcInternalError());
884 
885  // calculate shifts
886  unsigned int cumulated = 0;
887  for (unsigned int c = 0; c < n_buckets; ++c)
888  {
889  shifts[c] = cumulated;
890  for (types::subdomain_id i = 0; i < tria->locally_owned_subdomain();
891  ++i)
892  shifts[c] += all_dof_counts[c + n_buckets * i];
893  for (unsigned int i = 0;
894  i < Utilities::MPI::n_mpi_processes(tria->get_communicator());
895  ++i)
896  cumulated += all_dof_counts[c + n_buckets * i];
897  }
898 #else
899  (void)tria;
900  Assert(false, ExcInternalError());
901 #endif
902  }
903  else
904  {
905  shifts[0] = 0;
906  for (unsigned int c = 1; c < fe_collection.n_components(); ++c)
907  shifts[c] = shifts[c - 1] + component_to_dof_map[c - 1].size();
908  }
909 
910 
911 
912  // now concatenate all the
913  // components in the order the user
914  // desired to see
915  types::global_dof_index next_free_index = 0;
916  for (unsigned int component = 0; component < fe_collection.n_components();
917  ++component)
918  {
919  const typename std::vector<types::global_dof_index>::const_iterator
920  begin_of_component = component_to_dof_map[component].begin(),
921  end_of_component = component_to_dof_map[component].end();
922 
923  next_free_index = shifts[component];
924 
925  for (typename std::vector<types::global_dof_index>::const_iterator
926  dof_index = begin_of_component;
927  dof_index != end_of_component;
928  ++dof_index)
929  {
930  Assert(
931  start->get_dof_handler().locally_owned_dofs().index_within_set(
932  *dof_index) < new_indices.size(),
933  ExcInternalError());
934  new_indices[start->get_dof_handler()
935  .locally_owned_dofs()
936  .index_within_set(*dof_index)] = next_free_index++;
937  }
938  }
939 
940  return next_free_index;
941  }
942 
943 
944 
945  template <int dim, int spacedim>
946  void
948  {
949  std::vector<types::global_dof_index> renumbering(
951 
953  dof_handler.begin_active();
954  const typename DoFHandler<dim, spacedim>::level_cell_iterator end =
955  dof_handler.end();
956 
958  dim,
959  spacedim,
961  typename DoFHandler<dim, spacedim>::level_cell_iterator>(renumbering,
962  start,
963  end,
964  false);
965  if (result == 0)
966  return;
967 
968  // verify that the last numbered
969  // degree of freedom is either
970  // equal to the number of degrees
971  // of freedom in total (the
972  // sequential case) or in the
973  // distributed case at least
974  // makes sense
975  Assert((result == dof_handler.n_locally_owned_dofs()) ||
976  ((dof_handler.n_locally_owned_dofs() < dof_handler.n_dofs()) &&
977  (result <= dof_handler.n_dofs())),
978  ExcInternalError());
979 
980  dof_handler.renumber_dofs(renumbering);
981  }
982 
983 
984 
985  template <int dim, int spacedim>
986  void
988  {
989  std::vector<types::global_dof_index> renumbering(
990  dof_handler.n_dofs(), numbers::invalid_dof_index);
991 
993  dof_handler.begin_active();
994  const typename hp::DoFHandler<dim, spacedim>::level_cell_iterator end =
995  dof_handler.end();
996 
998  dim,
999  spacedim,
1001  typename hp::DoFHandler<dim, spacedim>::level_cell_iterator>(renumbering,
1002  start,
1003  end,
1004  false);
1005 
1006  if (result == 0)
1007  return;
1008 
1009  Assert(result == dof_handler.n_dofs(), ExcInternalError());
1010 
1011  dof_handler.renumber_dofs(renumbering);
1012  }
1013 
1014 
1015 
1016  template <int dim, int spacedim>
1017  void
1018  block_wise(DoFHandler<dim, spacedim> &dof_handler, const unsigned int level)
1019  {
1020  Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index,
1022 
1023  std::vector<types::global_dof_index> renumbering(
1024  dof_handler.n_dofs(level), numbers::invalid_dof_index);
1025 
1026  typename DoFHandler<dim, spacedim>::level_cell_iterator start =
1027  dof_handler.begin(level);
1028  typename DoFHandler<dim, spacedim>::level_cell_iterator end =
1029  dof_handler.end(level);
1030 
1032  dim,
1033  spacedim,
1034  typename DoFHandler<dim, spacedim>::level_cell_iterator,
1035  typename DoFHandler<dim, spacedim>::level_cell_iterator>(renumbering,
1036  start,
1037  end,
1038  true);
1039 
1040  if (result == 0)
1041  return;
1042 
1043  Assert(result == dof_handler.n_dofs(level), ExcInternalError());
1044 
1045  if (renumbering.size() != 0)
1046  dof_handler.renumber_dofs(level, renumbering);
1047  }
1048 
1049 
1050 
1051  template <int dim, int spacedim, class ITERATOR, class ENDITERATOR>
1053  compute_block_wise(std::vector<types::global_dof_index> &new_indices,
1054  const ITERATOR & start,
1055  const ENDITERATOR & end,
1056  const bool is_level_operation)
1057  {
1058  const hp::FECollection<dim, spacedim> fe_collection(
1059  start->get_dof_handler().get_fe_collection());
1060 
1061  // do nothing if the FE has only
1062  // one component
1063  if (fe_collection.n_blocks() == 1)
1064  {
1065  new_indices.resize(0);
1066  return 0;
1067  }
1068 
1069  // vector to hold the dof indices on
1070  // the cell we visit at a time
1071  std::vector<types::global_dof_index> local_dof_indices;
1072 
1073  // prebuilt list to which block
1074  // a given dof on a cell
1075  // should go.
1076  std::vector<std::vector<types::global_dof_index>> block_list(
1077  fe_collection.size());
1078  for (unsigned int f = 0; f < fe_collection.size(); ++f)
1079  {
1080  const FiniteElement<dim, spacedim> &fe = fe_collection[f];
1081  block_list[f].resize(fe.dofs_per_cell);
1082  for (unsigned int i = 0; i < fe.dofs_per_cell; ++i)
1083  block_list[f][i] = fe.system_to_block_index(i).first;
1084  }
1085 
1086  // set up a map where for each
1087  // block the respective degrees
1088  // of freedom are collected.
1089  //
1090  // note that this map is sorted by
1091  // block but that within each
1092  // block it is NOT sorted by
1093  // dof index. note also that some
1094  // dof indices are entered
1095  // multiply, so we will have to
1096  // take care of that
1097  std::vector<std::vector<types::global_dof_index>> block_to_dof_map(
1098  fe_collection.n_blocks());
1099  for (ITERATOR cell = start; cell != end; ++cell)
1100  {
1101  if (is_level_operation)
1102  {
1103  // we are dealing with mg dofs, skip foreign level cells:
1104  if (!cell->is_locally_owned_on_level())
1105  continue;
1106  }
1107  else
1108  {
1109  // we are dealing with active dofs, skip the loop if not locally
1110  // owned:
1111  if (!cell->is_locally_owned())
1112  continue;
1113  }
1114 
1115  // on each cell: get dof indices
1116  // and insert them into the global
1117  // list using their component
1118  const unsigned int fe_index = cell->active_fe_index();
1119  const unsigned int dofs_per_cell =
1120  fe_collection[fe_index].dofs_per_cell;
1121  local_dof_indices.resize(dofs_per_cell);
1122  cell->get_active_or_mg_dof_indices(local_dof_indices);
1123  for (unsigned int i = 0; i < dofs_per_cell; ++i)
1124  if (start->get_dof_handler().locally_owned_dofs().is_element(
1125  local_dof_indices[i]))
1126  block_to_dof_map[block_list[fe_index][i]].push_back(
1127  local_dof_indices[i]);
1128  }
1129 
1130  // now we've got all indices sorted
1131  // into buckets labeled by their
1132  // target block number. we've
1133  // only got to traverse this list
1134  // and assign the new indices
1135  //
1136  // however, we first want to sort
1137  // the indices entered into the
1138  // buckets to preserve the order
1139  // within each component and during
1140  // this also remove duplicate
1141  // entries
1142  for (unsigned int block = 0; block < fe_collection.n_blocks(); ++block)
1143  {
1144  std::sort(block_to_dof_map[block].begin(),
1145  block_to_dof_map[block].end());
1146  block_to_dof_map[block].erase(
1147  std::unique(block_to_dof_map[block].begin(),
1148  block_to_dof_map[block].end()),
1149  block_to_dof_map[block].end());
1150  }
1151 
1152  // calculate the number of locally owned
1153  // DoFs per bucket
1154  const unsigned int n_buckets = fe_collection.n_blocks();
1155  std::vector<types::global_dof_index> shifts(n_buckets);
1156 
1157  if (const parallel::Triangulation<dim, spacedim> *tria =
1158  (dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
1159  &start->get_dof_handler().get_triangulation())))
1160  {
1161 #ifdef DEAL_II_WITH_MPI
1162  std::vector<types::global_dof_index> local_dof_count(n_buckets);
1163 
1164  for (unsigned int c = 0; c < n_buckets; ++c)
1165  local_dof_count[c] = block_to_dof_map[c].size();
1166 
1167 
1168  // gather information from all CPUs
1169  std::vector<types::global_dof_index> all_dof_counts(
1170  fe_collection.n_components() *
1171  Utilities::MPI::n_mpi_processes(tria->get_communicator()));
1172 
1173  const int ierr = MPI_Allgather(local_dof_count.data(),
1174  n_buckets,
1175  DEAL_II_DOF_INDEX_MPI_TYPE,
1176  all_dof_counts.data(),
1177  n_buckets,
1178  DEAL_II_DOF_INDEX_MPI_TYPE,
1179  tria->get_communicator());
1180  AssertThrowMPI(ierr);
1181 
1182  for (unsigned int i = 0; i < n_buckets; ++i)
1183  Assert(
1184  all_dof_counts[n_buckets * tria->locally_owned_subdomain() + i] ==
1185  local_dof_count[i],
1186  ExcInternalError());
1187 
1188  // calculate shifts
1189  types::global_dof_index cumulated = 0;
1190  for (unsigned int c = 0; c < n_buckets; ++c)
1191  {
1192  shifts[c] = cumulated;
1193  for (types::subdomain_id i = 0; i < tria->locally_owned_subdomain();
1194  ++i)
1195  shifts[c] += all_dof_counts[c + n_buckets * i];
1196  for (unsigned int i = 0;
1197  i < Utilities::MPI::n_mpi_processes(tria->get_communicator());
1198  ++i)
1199  cumulated += all_dof_counts[c + n_buckets * i];
1200  }
1201 #else
1202  (void)tria;
1203  Assert(false, ExcInternalError());
1204 #endif
1205  }
1206  else
1207  {
1208  shifts[0] = 0;
1209  for (unsigned int c = 1; c < fe_collection.n_blocks(); ++c)
1210  shifts[c] = shifts[c - 1] + block_to_dof_map[c - 1].size();
1211  }
1212 
1213 
1214 
1215  // now concatenate all the
1216  // components in the order the user
1217  // desired to see
1218  types::global_dof_index next_free_index = 0;
1219  for (unsigned int block = 0; block < fe_collection.n_blocks(); ++block)
1220  {
1221  const typename std::vector<types::global_dof_index>::const_iterator
1222  begin_of_component = block_to_dof_map[block].begin(),
1223  end_of_component = block_to_dof_map[block].end();
1224 
1225  next_free_index = shifts[block];
1226 
1227  for (typename std::vector<types::global_dof_index>::const_iterator
1228  dof_index = begin_of_component;
1229  dof_index != end_of_component;
1230  ++dof_index)
1231  {
1232  Assert(
1233  start->get_dof_handler().locally_owned_dofs().index_within_set(
1234  *dof_index) < new_indices.size(),
1235  ExcInternalError());
1236  new_indices[start->get_dof_handler()
1237  .locally_owned_dofs()
1238  .index_within_set(*dof_index)] = next_free_index++;
1239  }
1240  }
1241 
1242  return next_free_index;
1243  }
1244 
1245 
1246 
1247  namespace
1248  {
1249  // Helper function for DoFRenumbering::hierarchical(). this function
1250  // recurses into the given cell or, if that should be an active (terminal)
1251  // cell, renumbers DoF indices on it. The function starts renumbering with
1252  // 'next_free_dof_index' and returns the first still unused DoF index at the
1253  // end of its operation.
1254  template <int dim, class CellIteratorType>
1256  compute_hierarchical_recursive(
1257  const types::global_dof_index next_free_dof_offset,
1258  const types::global_dof_index my_starting_index,
1259  const CellIteratorType & cell,
1260  const IndexSet & locally_owned_dof_indices,
1261  std::vector<types::global_dof_index> &new_indices)
1262  {
1263  types::global_dof_index current_next_free_dof_offset =
1264  next_free_dof_offset;
1265 
1266  if (cell->has_children())
1267  {
1268  // recursion
1269  for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
1270  ++c)
1271  current_next_free_dof_offset =
1272  compute_hierarchical_recursive<dim>(current_next_free_dof_offset,
1273  my_starting_index,
1274  cell->child(c),
1275  locally_owned_dof_indices,
1276  new_indices);
1277  }
1278  else
1279  {
1280  // this is a terminal cell. we need to renumber its DoF indices. there
1281  // are now three cases to decide:
1282  // - this is a sequential triangulation: we can just go ahead and
1283  // number
1284  // the DoFs in the order in which we encounter cells. in this case,
1285  // all cells are actually locally owned
1286  // - if this is a parallel::distributed::Triangulation, then we only
1287  // need to work on the locally owned cells since they contain
1288  // all locally owned DoFs.
1289  // - if this is a parallel::shared::Triangulation, then the same
1290  // applies
1291  //
1292  // in all cases, each processor starts new indices so that we get
1293  // a consecutive numbering on each processor, and disjoint ownership
1294  // of the global range of DoF indices
1295  if (cell->is_locally_owned())
1296  {
1297  // first get the existing DoF indices
1298  const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
1299  std::vector<types::global_dof_index> local_dof_indices(
1300  dofs_per_cell);
1301  cell->get_dof_indices(local_dof_indices);
1302 
1303  // then loop over the existing DoF indices on this cell
1304  // and see whether it has already been re-numbered (it
1305  // may have been on a face or vertex to a neighboring
1306  // cell that we have encountered before). if not,
1307  // give it a new number and store that number in the
1308  // output array (new_indices)
1309  //
1310  // if this is a parallel triangulation and a DoF index is
1311  // not locally owned, then don't touch it. since
1312  // we don't actually *change* DoF indices (just record new
1313  // numbers in an array), we don't need to worry about
1314  // the decision whether a DoF is locally owned or not changing
1315  // as we progress in renumbering DoFs -- all adjacent cells
1316  // will always agree that a DoF is locally owned or not.
1317  // that said, the first cell to encounter a locally owned DoF
1318  // gets to number it, so the order in which we traverse cells
1319  // matters
1320  for (unsigned int i = 0; i < dofs_per_cell; ++i)
1321  if (locally_owned_dof_indices.is_element(local_dof_indices[i]))
1322  {
1323  // this is a locally owned DoF, assign new number if not
1324  // assigned a number yet
1325  const unsigned int idx =
1326  locally_owned_dof_indices.index_within_set(
1327  local_dof_indices[i]);
1328  if (new_indices[idx] == numbers::invalid_dof_index)
1329  {
1330  new_indices[idx] =
1331  my_starting_index + current_next_free_dof_offset;
1332  ++current_next_free_dof_offset;
1333  }
1334  }
1335  }
1336  }
1337 
1338  return current_next_free_dof_offset;
1339  }
1340  } // namespace
1341 
1342 
1343 
1344  template <int dim>
1345  void
1347  {
1348  std::vector<types::global_dof_index> renumbering(
1350 
1351  types::global_dof_index next_free_dof_offset = 0;
1352  const IndexSet locally_owned = dof_handler.locally_owned_dofs();
1353 
1354  // in the function we call recursively, we want to number DoFs so
1355  // that global cell zero starts with DoF zero, regardless of how
1356  // DoFs were previously numbered. to this end, we need to figure
1357  // out which DoF index the current processor should start with.
1358  //
1359  // if this is a sequential triangulation, then obviously the starting
1360  // index is zero. otherwise, make sure we get contiguous, successive
1361  // ranges on each processor. note that since the number of locally owned
1362  // DoFs is an invariant under renumbering, we can easily compute this
1363  // starting index by just accumulating over the number of locally owned
1364  // DoFs for all previous processes
1365  types::global_dof_index my_starting_index = 0;
1366 
1367  if (const parallel::Triangulation<dim> *tria =
1368  dynamic_cast<const parallel::Triangulation<dim> *>(
1369  &dof_handler.get_triangulation()))
1370  {
1371  const std::vector<types::global_dof_index>
1372  &n_locally_owned_dofs_per_processor =
1373  dof_handler.n_locally_owned_dofs_per_processor();
1374  my_starting_index =
1375  std::accumulate(n_locally_owned_dofs_per_processor.begin(),
1376  n_locally_owned_dofs_per_processor.begin() +
1377  tria->locally_owned_subdomain(),
1379  }
1380 
1382  dynamic_cast<const parallel::distributed::Triangulation<dim> *>(
1383  &dof_handler.get_triangulation()))
1384  {
1385 #ifdef DEAL_II_WITH_P4EST
1386  // this is a distributed Triangulation. we need to traverse the coarse
1387  // cells in the order p4est does to match the z-order actually used
1388  // by p4est. this requires using the renumbering of coarse cells
1389  // we do before we hand things off to p4est
1390  for (unsigned int c = 0; c < tria->n_cells(0); ++c)
1391  {
1392  const unsigned int coarse_cell_index =
1393  tria->get_p4est_tree_to_coarse_cell_permutation()[c];
1394 
1395  const typename DoFHandler<dim>::level_cell_iterator this_cell(
1396  tria, 0, coarse_cell_index, &dof_handler);
1397 
1398  next_free_dof_offset =
1399  compute_hierarchical_recursive<dim>(next_free_dof_offset,
1400  my_starting_index,
1401  this_cell,
1402  locally_owned,
1403  renumbering);
1404  }
1405 #else
1406  Assert(false, ExcNotImplemented());
1407 #endif
1408  }
1409  else
1410  {
1411  // this is not a distributed Triangulation, so we can traverse coarse
1412  // cells in the normal order
1413  for (typename DoFHandler<dim>::cell_iterator cell =
1414  dof_handler.begin(0);
1415  cell != dof_handler.end(0);
1416  ++cell)
1417  next_free_dof_offset =
1418  compute_hierarchical_recursive<dim>(next_free_dof_offset,
1419  my_starting_index,
1420  cell,
1421  locally_owned,
1422  renumbering);
1423  }
1424 
1425  // verify that the last numbered degree of freedom is either
1426  // equal to the number of degrees of freedom in total (the
1427  // sequential case) or in the distributed case at least
1428  // makes sense
1429  Assert((next_free_dof_offset == dof_handler.n_locally_owned_dofs()) ||
1430  ((dof_handler.n_locally_owned_dofs() < dof_handler.n_dofs()) &&
1431  (next_free_dof_offset <= dof_handler.n_dofs())),
1432  ExcInternalError());
1433 
1434  // make sure that all local DoFs got new numbers assigned
1435  Assert(std::find(renumbering.begin(),
1436  renumbering.end(),
1437  numbers::invalid_dof_index) == renumbering.end(),
1438  ExcInternalError());
1439 
1440  dof_handler.renumber_dofs(renumbering);
1441  }
1442 
1443 
1444 
1445  template <typename DoFHandlerType>
1446  void
1447  sort_selected_dofs_back(DoFHandlerType & dof_handler,
1448  const std::vector<bool> &selected_dofs)
1449  {
1450  std::vector<types::global_dof_index> renumbering(
1451  dof_handler.n_dofs(), numbers::invalid_dof_index);
1452  compute_sort_selected_dofs_back(renumbering, dof_handler, selected_dofs);
1453 
1454  dof_handler.renumber_dofs(renumbering);
1455  }
1456 
1457 
1458 
1459  template <typename DoFHandlerType>
1460  void
1461  sort_selected_dofs_back(DoFHandlerType & dof_handler,
1462  const std::vector<bool> &selected_dofs,
1463  const unsigned int level)
1464  {
1465  Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index,
1467 
1468  std::vector<types::global_dof_index> renumbering(
1469  dof_handler.n_dofs(level), numbers::invalid_dof_index);
1470  compute_sort_selected_dofs_back(renumbering,
1471  dof_handler,
1472  selected_dofs,
1473  level);
1474 
1475  dof_handler.renumber_dofs(level, renumbering);
1476  }
1477 
1478 
1479 
1480  template <typename DoFHandlerType>
1481  void
1483  std::vector<types::global_dof_index> &new_indices,
1484  const DoFHandlerType & dof_handler,
1485  const std::vector<bool> & selected_dofs)
1486  {
1487  const types::global_dof_index n_dofs = dof_handler.n_dofs();
1488  Assert(selected_dofs.size() == n_dofs,
1489  ExcDimensionMismatch(selected_dofs.size(), n_dofs));
1490 
1491  // re-sort the dofs according to
1492  // their selection state
1493  Assert(new_indices.size() == n_dofs,
1494  ExcDimensionMismatch(new_indices.size(), n_dofs));
1495 
1496  const types::global_dof_index n_selected_dofs =
1497  std::count(selected_dofs.begin(), selected_dofs.end(), false);
1498 
1499  types::global_dof_index next_unselected = 0;
1500  types::global_dof_index next_selected = n_selected_dofs;
1501  for (types::global_dof_index i = 0; i < n_dofs; ++i)
1502  if (selected_dofs[i] == false)
1503  {
1504  new_indices[i] = next_unselected;
1505  ++next_unselected;
1506  }
1507  else
1508  {
1509  new_indices[i] = next_selected;
1510  ++next_selected;
1511  };
1512  Assert(next_unselected == n_selected_dofs, ExcInternalError());
1513  Assert(next_selected == n_dofs, ExcInternalError());
1514  }
1515 
1516 
1517 
1518  template <typename DoFHandlerType>
1519  void
1521  std::vector<types::global_dof_index> &new_indices,
1522  const DoFHandlerType & dof_handler,
1523  const std::vector<bool> & selected_dofs,
1524  const unsigned int level)
1525  {
1526  Assert(dof_handler.n_dofs(level) != numbers::invalid_dof_index,
1528 
1529  const unsigned int n_dofs = dof_handler.n_dofs(level);
1530  Assert(selected_dofs.size() == n_dofs,
1531  ExcDimensionMismatch(selected_dofs.size(), n_dofs));
1532 
1533  // re-sort the dofs according to
1534  // their selection state
1535  Assert(new_indices.size() == n_dofs,
1536  ExcDimensionMismatch(new_indices.size(), n_dofs));
1537 
1538  const unsigned int n_selected_dofs =
1539  std::count(selected_dofs.begin(), selected_dofs.end(), false);
1540 
1541  unsigned int next_unselected = 0;
1542  unsigned int next_selected = n_selected_dofs;
1543  for (unsigned int i = 0; i < n_dofs; ++i)
1544  if (selected_dofs[i] == false)
1545  {
1546  new_indices[i] = next_unselected;
1547  ++next_unselected;
1548  }
1549  else
1550  {
1551  new_indices[i] = next_selected;
1552  ++next_selected;
1553  };
1554  Assert(next_unselected == n_selected_dofs, ExcInternalError());
1555  Assert(next_selected == n_dofs, ExcInternalError());
1556  }
1557 
1558 
1559 
1560  template <typename DoFHandlerType>
1561  void
1563  DoFHandlerType & dof,
1564  const std::vector<typename DoFHandlerType::active_cell_iterator> &cells)
1565  {
1566  std::vector<types::global_dof_index> renumbering(dof.n_dofs());
1567  std::vector<types::global_dof_index> reverse(dof.n_dofs());
1568  compute_cell_wise(renumbering, reverse, dof, cells);
1569 
1570  dof.renumber_dofs(renumbering);
1571  }
1572 
1573 
1574  template <typename DoFHandlerType>
1575  void
1577  std::vector<types::global_dof_index> &new_indices,
1578  std::vector<types::global_dof_index> &reverse,
1579  const DoFHandlerType & dof,
1580  const typename std::vector<typename DoFHandlerType::active_cell_iterator>
1581  &cells)
1582  {
1583  Assert(cells.size() == dof.get_triangulation().n_active_cells(),
1584  ExcDimensionMismatch(cells.size(),
1585  dof.get_triangulation().n_active_cells()));
1586 
1587  types::global_dof_index n_global_dofs = dof.n_dofs();
1588 
1589  // Actually, we compute the
1590  // inverse of the reordering
1591  // vector, called reverse here.
1592  // Later, irs inverse is computed
1593  // into new_indices, which is the
1594  // return argument.
1595 
1596  Assert(new_indices.size() == n_global_dofs,
1597  ExcDimensionMismatch(new_indices.size(), n_global_dofs));
1598  Assert(reverse.size() == n_global_dofs,
1599  ExcDimensionMismatch(reverse.size(), n_global_dofs));
1600 
1601  // For continuous elements, we must
1602  // make sure, that each dof is
1603  // reordered only once.
1604  std::vector<bool> already_sorted(n_global_dofs, false);
1605  std::vector<types::global_dof_index> cell_dofs;
1606 
1607  unsigned int global_index = 0;
1608 
1609  typename std::vector<
1610  typename DoFHandlerType::active_cell_iterator>::const_iterator cell;
1611 
1612  for (cell = cells.begin(); cell != cells.end(); ++cell)
1613  {
1614  // Determine the number of dofs
1615  // on this cell and reinit the
1616  // vector storing these
1617  // numbers.
1618  unsigned int n_cell_dofs = (*cell)->get_fe().n_dofs_per_cell();
1619  cell_dofs.resize(n_cell_dofs);
1620 
1621  (*cell)->get_active_or_mg_dof_indices(cell_dofs);
1622 
1623  // Sort here to make sure that
1624  // degrees of freedom inside a
1625  // single cell are in the same
1626  // order after renumbering.
1627  std::sort(cell_dofs.begin(), cell_dofs.end());
1628 
1629  for (unsigned int i = 0; i < n_cell_dofs; ++i)
1630  {
1631  if (!already_sorted[cell_dofs[i]])
1632  {
1633  already_sorted[cell_dofs[i]] = true;
1634  reverse[global_index++] = cell_dofs[i];
1635  }
1636  }
1637  }
1638  Assert(global_index == n_global_dofs,
1639  ExcMessage(
1640  "Traversing over the given set of cells did not cover all "
1641  "degrees of freedom in the DoFHandler. Does the set of cells "
1642  "not include all active cells?"));
1643 
1644  for (types::global_dof_index i = 0; i < reverse.size(); ++i)
1645  new_indices[reverse[i]] = i;
1646  }
1647 
1648 
1649 
1650  template <typename DoFHandlerType>
1651  void
1652  cell_wise(
1653  DoFHandlerType & dof,
1654  const unsigned int level,
1655  const typename std::vector<typename DoFHandlerType::level_cell_iterator>
1656  &cells)
1657  {
1658  Assert(dof.n_dofs(level) != numbers::invalid_dof_index,
1660 
1661  std::vector<types::global_dof_index> renumbering(dof.n_dofs(level));
1662  std::vector<types::global_dof_index> reverse(dof.n_dofs(level));
1663 
1664  compute_cell_wise(renumbering, reverse, dof, level, cells);
1665  dof.renumber_dofs(level, renumbering);
1666  }
1667 
1668 
1669 
1670  template <typename DoFHandlerType>
1671  void
1673  std::vector<types::global_dof_index> &new_order,
1674  std::vector<types::global_dof_index> &reverse,
1675  const DoFHandlerType & dof,
1676  const unsigned int level,
1677  const typename std::vector<typename DoFHandlerType::level_cell_iterator>
1678  &cells)
1679  {
1680  Assert(cells.size() == dof.get_triangulation().n_cells(level),
1681  ExcDimensionMismatch(cells.size(),
1682  dof.get_triangulation().n_cells(level)));
1683  Assert(new_order.size() == dof.n_dofs(level),
1684  ExcDimensionMismatch(new_order.size(), dof.n_dofs(level)));
1685  Assert(reverse.size() == dof.n_dofs(level),
1686  ExcDimensionMismatch(reverse.size(), dof.n_dofs(level)));
1687 
1688  unsigned int n_global_dofs = dof.n_dofs(level);
1689  unsigned int n_cell_dofs = dof.get_fe().n_dofs_per_cell();
1690 
1691  std::vector<bool> already_sorted(n_global_dofs, false);
1692  std::vector<types::global_dof_index> cell_dofs(n_cell_dofs);
1693 
1694  unsigned int global_index = 0;
1695 
1696  typename std::vector<
1697  typename DoFHandlerType::level_cell_iterator>::const_iterator cell;
1698 
1699  for (cell = cells.begin(); cell != cells.end(); ++cell)
1700  {
1701  Assert((*cell)->level() == (int)level, ExcInternalError());
1702 
1703  (*cell)->get_active_or_mg_dof_indices(cell_dofs);
1704  std::sort(cell_dofs.begin(), cell_dofs.end());
1705 
1706  for (unsigned int i = 0; i < n_cell_dofs; ++i)
1707  {
1708  if (!already_sorted[cell_dofs[i]])
1709  {
1710  already_sorted[cell_dofs[i]] = true;
1711  reverse[global_index++] = cell_dofs[i];
1712  }
1713  }
1714  }
1715  Assert(global_index == n_global_dofs,
1716  ExcMessage(
1717  "Traversing over the given set of cells did not cover all "
1718  "degrees of freedom in the DoFHandler. Does the set of cells "
1719  "not include all cells of the specified level?"));
1720 
1721  for (types::global_dof_index i = 0; i < new_order.size(); ++i)
1722  new_order[reverse[i]] = i;
1723  }
1724 
1725 
1726 
1727  template <typename DoFHandlerType>
1728  void
1729  downstream(DoFHandlerType & dof,
1731  const bool dof_wise_renumbering)
1732  {
1733  std::vector<types::global_dof_index> renumbering(dof.n_dofs());
1734  std::vector<types::global_dof_index> reverse(dof.n_dofs());
1736  renumbering, reverse, dof, direction, dof_wise_renumbering);
1737 
1738  dof.renumber_dofs(renumbering);
1739  }
1740 
1741 
1742 
1743  template <typename DoFHandlerType>
1744  void
1746  std::vector<types::global_dof_index> & new_indices,
1747  std::vector<types::global_dof_index> & reverse,
1748  const DoFHandlerType & dof,
1750  const bool dof_wise_renumbering)
1751  {
1752  Assert((dynamic_cast<
1753  const parallel::Triangulation<DoFHandlerType::dimension,
1754  DoFHandlerType::space_dimension> *>(
1755  &dof.get_triangulation()) == nullptr),
1756  ExcNotImplemented());
1757 
1758  if (dof_wise_renumbering == false)
1759  {
1760  std::vector<typename DoFHandlerType::active_cell_iterator>
1761  ordered_cells;
1762  ordered_cells.reserve(dof.get_triangulation().n_active_cells());
1763  const CompareDownstream<typename DoFHandlerType::active_cell_iterator,
1764  DoFHandlerType::space_dimension>
1765  comparator(direction);
1766 
1767  typename DoFHandlerType::active_cell_iterator p = dof.begin_active();
1768  typename DoFHandlerType::active_cell_iterator end = dof.end();
1769 
1770  while (p != end)
1771  {
1772  ordered_cells.push_back(p);
1773  ++p;
1774  }
1775  std::sort(ordered_cells.begin(), ordered_cells.end(), comparator);
1776 
1777  compute_cell_wise(new_indices, reverse, dof, ordered_cells);
1778  }
1779  else
1780  {
1781  // similar code as for
1782  // DoFTools::map_dofs_to_support_points, but
1783  // need to do this for general DoFHandlerType classes and
1784  // want to be able to sort the result
1785  // (otherwise, could use something like
1786  // DoFTools::map_support_points_to_dofs)
1787  const unsigned int n_dofs = dof.n_dofs();
1788  std::vector<
1789  std::pair<Point<DoFHandlerType::space_dimension>, unsigned int>>
1790  support_point_list(n_dofs);
1791 
1792  const hp::FECollection<DoFHandlerType::dimension> &fe_collection =
1793  dof.get_fe_collection();
1794  Assert(fe_collection[0].has_support_points(),
1795  typename FiniteElement<
1796  DoFHandlerType::dimension>::ExcFEHasNoSupportPoints());
1797  hp::QCollection<DoFHandlerType::dimension> quadrature_collection;
1798  for (unsigned int comp = 0; comp < fe_collection.size(); ++comp)
1799  {
1800  Assert(fe_collection[comp].has_support_points(),
1801  typename FiniteElement<
1802  DoFHandlerType::dimension>::ExcFEHasNoSupportPoints());
1803  quadrature_collection.push_back(
1805  fe_collection[comp].get_unit_support_points()));
1806  }
1808  hp_fe_values(fe_collection,
1809  quadrature_collection,
1811 
1812  std::vector<bool> already_touched(n_dofs, false);
1813 
1814  std::vector<types::global_dof_index> local_dof_indices;
1815  typename DoFHandlerType::active_cell_iterator begin =
1816  dof.begin_active();
1817  typename DoFHandlerType::active_cell_iterator end = dof.end();
1818  for (; begin != end; ++begin)
1819  {
1820  const unsigned int dofs_per_cell = begin->get_fe().dofs_per_cell;
1821  local_dof_indices.resize(dofs_per_cell);
1822  hp_fe_values.reinit(begin);
1823  const FEValues<DoFHandlerType::dimension> &fe_values =
1824  hp_fe_values.get_present_fe_values();
1825  begin->get_active_or_mg_dof_indices(local_dof_indices);
1826  const std::vector<Point<DoFHandlerType::space_dimension>> &points =
1827  fe_values.get_quadrature_points();
1828  for (unsigned int i = 0; i < dofs_per_cell; ++i)
1829  if (!already_touched[local_dof_indices[i]])
1830  {
1831  support_point_list[local_dof_indices[i]].first = points[i];
1832  support_point_list[local_dof_indices[i]].second =
1833  local_dof_indices[i];
1834  already_touched[local_dof_indices[i]] = true;
1835  }
1836  }
1837 
1839  direction);
1840  std::sort(support_point_list.begin(),
1841  support_point_list.end(),
1842  comparator);
1843  for (types::global_dof_index i = 0; i < n_dofs; ++i)
1844  new_indices[support_point_list[i].second] = i;
1845  }
1846  }
1847 
1848 
1849 
1850  template <typename DoFHandlerType>
1851  void
1852  downstream(DoFHandlerType & dof,
1853  const unsigned int level,
1855  const bool dof_wise_renumbering)
1856  {
1857  std::vector<types::global_dof_index> renumbering(dof.n_dofs(level));
1858  std::vector<types::global_dof_index> reverse(dof.n_dofs(level));
1860  renumbering, reverse, dof, level, direction, dof_wise_renumbering);
1861 
1862  dof.renumber_dofs(level, renumbering);
1863  }
1864 
1865 
1866 
1867  template <typename DoFHandlerType>
1868  void
1870  std::vector<types::global_dof_index> & new_indices,
1871  std::vector<types::global_dof_index> & reverse,
1872  const DoFHandlerType & dof,
1873  const unsigned int level,
1875  const bool dof_wise_renumbering)
1876  {
1877  if (dof_wise_renumbering == false)
1878  {
1879  std::vector<typename DoFHandlerType::level_cell_iterator> ordered_cells;
1880  ordered_cells.reserve(dof.get_triangulation().n_cells(level));
1881  const CompareDownstream<typename DoFHandlerType::level_cell_iterator,
1882  DoFHandlerType::space_dimension>
1883  comparator(direction);
1884 
1885  typename DoFHandlerType::level_cell_iterator p = dof.begin(level);
1886  typename DoFHandlerType::level_cell_iterator end = dof.end(level);
1887 
1888  while (p != end)
1889  {
1890  ordered_cells.push_back(p);
1891  ++p;
1892  }
1893  std::sort(ordered_cells.begin(), ordered_cells.end(), comparator);
1894 
1895  compute_cell_wise(new_indices, reverse, dof, level, ordered_cells);
1896  }
1897  else
1898  {
1899  Assert(dof.get_fe().has_support_points(),
1900  typename FiniteElement<
1901  DoFHandlerType::dimension>::ExcFEHasNoSupportPoints());
1902  const unsigned int n_dofs = dof.n_dofs(level);
1903  std::vector<
1904  std::pair<Point<DoFHandlerType::space_dimension>, unsigned int>>
1905  support_point_list(n_dofs);
1906 
1908  dof.get_fe().get_unit_support_points());
1910  fe_values(dof.get_fe(), q_dummy, update_quadrature_points);
1911 
1912  std::vector<bool> already_touched(dof.n_dofs(), false);
1913 
1914  const unsigned int dofs_per_cell = dof.get_fe().dofs_per_cell;
1915  std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1916  typename DoFHandlerType::level_cell_iterator begin = dof.begin(level);
1917  typename DoFHandlerType::level_cell_iterator end = dof.end(level);
1918  for (; begin != end; ++begin)
1919  {
1920  const typename Triangulation<
1921  DoFHandlerType::dimension,
1922  DoFHandlerType::space_dimension>::cell_iterator &begin_tria =
1923  begin;
1924  begin->get_active_or_mg_dof_indices(local_dof_indices);
1925  fe_values.reinit(begin_tria);
1926  const std::vector<Point<DoFHandlerType::space_dimension>> &points =
1927  fe_values.get_quadrature_points();
1928  for (unsigned int i = 0; i < dofs_per_cell; ++i)
1929  if (!already_touched[local_dof_indices[i]])
1930  {
1931  support_point_list[local_dof_indices[i]].first = points[i];
1932  support_point_list[local_dof_indices[i]].second =
1933  local_dof_indices[i];
1934  already_touched[local_dof_indices[i]] = true;
1935  }
1936  }
1937 
1939  direction);
1940  std::sort(support_point_list.begin(),
1941  support_point_list.end(),
1942  comparator);
1943  for (types::global_dof_index i = 0; i < n_dofs; ++i)
1944  new_indices[support_point_list[i].second] = i;
1945  }
1946  }
1947 
1948 
1949 
1953  namespace internal
1954  {
1955  template <int dim>
1956  struct ClockCells
1957  {
1961  const Point<dim> &center;
1965  bool counter;
1966 
1970  ClockCells(const Point<dim> &center, bool counter)
1971  : center(center)
1972  , counter(counter)
1973  {}
1974 
1978  template <class DHCellIterator>
1979  bool
1980  operator()(const DHCellIterator &c1, const DHCellIterator &c2) const
1981  {
1982  // dispatch to
1983  // dimension-dependent functions
1984  return compare(c1, c2, std::integral_constant<int, dim>());
1985  }
1986 
1987  private:
1991  template <class DHCellIterator, int xdim>
1992  bool
1993  compare(const DHCellIterator &c1,
1994  const DHCellIterator &c2,
1995  std::integral_constant<int, xdim>) const
1996  {
1997  const Tensor<1, dim> v1 = c1->center() - center;
1998  const Tensor<1, dim> v2 = c2->center() - center;
1999  const double s1 = std::atan2(v1[0], v1[1]);
2000  const double s2 = std::atan2(v2[0], v2[1]);
2001  return (counter ? (s1 > s2) : (s2 > s1));
2002  }
2003 
2004 
2009  template <class DHCellIterator>
2010  bool
2011  compare(const DHCellIterator &,
2012  const DHCellIterator &,
2013  std::integral_constant<int, 1>) const
2014  {
2015  Assert(dim >= 2,
2016  ExcMessage("This operation only makes sense for dim>=2."));
2017  return false;
2018  }
2019  };
2020  } // namespace internal
2021 
2022 
2023 
2024  template <typename DoFHandlerType>
2025  void
2026  clockwise_dg(DoFHandlerType & dof,
2028  const bool counter)
2029  {
2030  std::vector<types::global_dof_index> renumbering(dof.n_dofs());
2031  compute_clockwise_dg(renumbering, dof, center, counter);
2032 
2033  dof.renumber_dofs(renumbering);
2034  }
2035 
2036 
2037 
2038  template <typename DoFHandlerType>
2039  void
2040  compute_clockwise_dg(std::vector<types::global_dof_index> &new_indices,
2041  const DoFHandlerType & dof,
2043  const bool counter)
2044  {
2045  std::vector<typename DoFHandlerType::active_cell_iterator> ordered_cells;
2046  ordered_cells.reserve(dof.get_triangulation().n_active_cells());
2047  internal::ClockCells<DoFHandlerType::space_dimension> comparator(center,
2048  counter);
2049 
2050  typename DoFHandlerType::active_cell_iterator p = dof.begin_active();
2051  typename DoFHandlerType::active_cell_iterator end = dof.end();
2052 
2053  while (p != end)
2054  {
2055  ordered_cells.push_back(p);
2056  ++p;
2057  }
2058  std::sort(ordered_cells.begin(), ordered_cells.end(), comparator);
2059 
2060  std::vector<types::global_dof_index> reverse(new_indices.size());
2061  compute_cell_wise(new_indices, reverse, dof, ordered_cells);
2062  }
2063 
2064 
2065 
2066  template <typename DoFHandlerType>
2067  void
2068  clockwise_dg(DoFHandlerType & dof,
2069  const unsigned int level,
2071  const bool counter)
2072  {
2073  std::vector<typename DoFHandlerType::level_cell_iterator> ordered_cells;
2074  ordered_cells.reserve(dof.get_triangulation().n_active_cells());
2075  internal::ClockCells<DoFHandlerType::space_dimension> comparator(center,
2076  counter);
2077 
2078  typename DoFHandlerType::level_cell_iterator p = dof.begin(level);
2079  typename DoFHandlerType::level_cell_iterator end = dof.end(level);
2080 
2081  while (p != end)
2082  {
2083  ordered_cells.push_back(p);
2084  ++p;
2085  }
2086  std::sort(ordered_cells.begin(), ordered_cells.end(), comparator);
2087 
2088  cell_wise(dof, level, ordered_cells);
2089  }
2090 
2091 
2092 
2093  template <typename DoFHandlerType>
2094  void
2095  random(DoFHandlerType &dof_handler)
2096  {
2097  std::vector<types::global_dof_index> renumbering(
2098  dof_handler.n_dofs(), numbers::invalid_dof_index);
2099  compute_random(renumbering, dof_handler);
2100 
2101  dof_handler.renumber_dofs(renumbering);
2102  }
2103 
2104 
2105 
2106  template <typename DoFHandlerType>
2107  void
2108  compute_random(std::vector<types::global_dof_index> &new_indices,
2109  const DoFHandlerType & dof_handler)
2110  {
2111  const types::global_dof_index n_dofs = dof_handler.n_dofs();
2112  Assert(new_indices.size() == n_dofs,
2113  ExcDimensionMismatch(new_indices.size(), n_dofs));
2114 
2115  for (unsigned int i = 0; i < n_dofs; ++i)
2116  new_indices[i] = i;
2117 
2118  // shuffle the elements; the following is essentially std::shuffle (which
2119  // is new in C++11) but with a boost URNG
2120  ::boost::mt19937 random_number_generator;
2121  for (unsigned int i = 1; i < n_dofs; ++i)
2122  {
2123  // get a random number between 0 and i (inclusive)
2124  const unsigned int j =
2125  ::boost::random::uniform_int_distribution<>(0, i)(
2126  random_number_generator);
2127 
2128  // if possible, swap the elements
2129  if (i != j)
2130  std::swap(new_indices[i], new_indices[j]);
2131  }
2132  }
2133 
2134 
2135 
2136  template <typename DoFHandlerType>
2137  void
2138  subdomain_wise(DoFHandlerType &dof_handler)
2139  {
2140  Assert(
2141  (!dynamic_cast<
2142  const parallel::Triangulation<DoFHandlerType::dimension,
2143  DoFHandlerType::space_dimension> *>(
2144  &dof_handler.get_triangulation())),
2145  ExcMessage(
2146  "Parallel triangulations are already enumerated according to their MPI process id."));
2147 
2148  std::vector<types::global_dof_index> renumbering(
2149  dof_handler.n_dofs(), numbers::invalid_dof_index);
2150  compute_subdomain_wise(renumbering, dof_handler);
2151 
2152  dof_handler.renumber_dofs(renumbering);
2153  }
2154 
2155 
2156 
2157  template <typename DoFHandlerType>
2158  void
2159  compute_subdomain_wise(std::vector<types::global_dof_index> &new_dof_indices,
2160  const DoFHandlerType & dof_handler)
2161  {
2162  const types::global_dof_index n_dofs = dof_handler.n_dofs();
2163  Assert(new_dof_indices.size() == n_dofs,
2164  ExcDimensionMismatch(new_dof_indices.size(), n_dofs));
2165 
2166  // first get the association of each dof
2167  // with a subdomain and determine the total
2168  // number of subdomain ids used
2169  std::vector<types::subdomain_id> subdomain_association(n_dofs);
2170  DoFTools::get_subdomain_association(dof_handler, subdomain_association);
2171  const unsigned int n_subdomains =
2172  *std::max_element(subdomain_association.begin(),
2173  subdomain_association.end()) +
2174  1;
2175 
2176  // then renumber the subdomains by first
2177  // looking at those belonging to subdomain
2178  // 0, then those of subdomain 1, etc. note
2179  // that the algorithm is stable, i.e. if
2180  // two dofs i,j have i<j and belong to the
2181  // same subdomain, then they will be in
2182  // this order also after reordering
2183  std::fill(new_dof_indices.begin(),
2184  new_dof_indices.end(),
2186  types::global_dof_index next_free_index = 0;
2187  for (types::subdomain_id subdomain = 0; subdomain < n_subdomains;
2188  ++subdomain)
2189  for (types::global_dof_index i = 0; i < n_dofs; ++i)
2190  if (subdomain_association[i] == subdomain)
2191  {
2192  Assert(new_dof_indices[i] == numbers::invalid_dof_index,
2193  ExcInternalError());
2194  new_dof_indices[i] = next_free_index;
2195  ++next_free_index;
2196  }
2197 
2198  // we should have numbered all dofs
2199  Assert(next_free_index == n_dofs, ExcInternalError());
2200  Assert(std::find(new_dof_indices.begin(),
2201  new_dof_indices.end(),
2202  numbers::invalid_dof_index) == new_dof_indices.end(),
2203  ExcInternalError());
2204  }
2205 
2206 } // namespace DoFRenumbering
2207 
2208 
2209 
2210 /*-------------- Explicit Instantiations -------------------------------*/
2211 #include "dof_renumbering.inst"
2212 
2213 
2214 DEAL_II_NAMESPACE_CLOSE
void compute_downstream(std::vector< types::global_dof_index > &new_dof_indices, std::vector< types::global_dof_index > &reverse, const DoFHandlerType &dof_handler, const Tensor< 1, DoFHandlerType::space_dimension > &direction, const bool dof_wise_renumbering)
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: dof_handler.cc:943
std::pair< unsigned int, types::global_dof_index > system_to_block_index(const unsigned int component) const
Definition: fe.h:3235
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
void downstream(DoFHandlerType &dof_handler, const Tensor< 1, DoFHandlerType::space_dimension > &direction, const bool dof_wise_renumbering=false)
types::global_dof_index n_dofs() const
void minimum_degree(DoFHandlerType &dof_handler, const bool reversed_numbering=false, const bool use_constraints=false)
void renumber_dofs(const std::vector< types::global_dof_index > &new_numbers)
void compute_cell_wise(std::vector< types::global_dof_index > &renumbering, std::vector< types::global_dof_index > &inverse_renumbering, const DoFHandlerType &dof_handler, const std::vector< typename DoFHandlerType::active_cell_iterator > &cell_order)
void compute_king_ordering(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &, const bool reversed_numbering=false, const bool use_constraints=false)
void sort_selected_dofs_back(DoFHandlerType &dof_handler, const std::vector< bool > &selected_dofs)
void get_subdomain_association(const DoFHandlerType &dof_handler, std::vector< types::subdomain_id > &subdomain)
Definition: dof_tools.cc:1522
void hierarchical(DoFHandler< dim > &dof_handler)
size_type n_elements() const
Definition: index_set.h:1743
void make_sparsity_pattern(const DoFHandlerType &dof_handler, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:573
void reorder_Cuthill_McKee(const DynamicSparsityPattern &sparsity, std::vector< DynamicSparsityPattern::size_type > &new_indices, const std::vector< DynamicSparsityPattern::size_type > &starting_indices=std::vector< DynamicSparsityPattern::size_type >())
void component_wise(DoFHandlerType &dof_handler, const std::vector< unsigned int > &target_component=std::vector< unsigned int >())
STL namespace.
unsigned int size() const
Transformed quadrature points.
const Triangulation< dim, spacedim > & get_triangulation() const
types::global_dof_index compute_component_wise(std::vector< types::global_dof_index > &new_dof_indices, const CellIterator &start, const typename identity< CellIterator >::type &end, const std::vector< unsigned int > &target_component, const bool is_level_operation)
const std::vector< types::global_dof_index > & n_locally_owned_dofs_per_processor() const
size_type size() const
Definition: index_set.h:1611
bool is_primitive() const
Definition: fe.h:3285
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:105
void make_hanging_node_constraints(const DoFHandlerType &dof_handler, AffineConstraints< number > &constraints)
unsigned long long int global_dof_index
Definition: types.h:72
static::ExceptionBase & ExcDoFHandlerNotInitialized()
active_cell_iterator begin_active(const unsigned int level=0) const
typename ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:194
void random(DoFHandlerType &dof_handler)
static::ExceptionBase & ExcMessage(std::string arg1)
const std::vector< Point< spacedim > > & get_quadrature_points() const
void compute_minimum_degree(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &, const bool reversed_numbering=false, const bool use_constraints=false)
unsigned int subdomain_id
Definition: types.h:43
void Cuthill_McKee(DoFHandlerType &dof_handler, const bool reversed_numbering=false, const bool use_constraints=false)
void subtract_set(const IndexSet &other)
Definition: index_set.cc:265
#define Assert(cond, exc)
Definition: exceptions.h:1227
types::global_dof_index n_dofs() const
void compute_subdomain_wise(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &dof_handler)
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
unsigned int n_locally_owned_dofs() const
const FiniteElement< dim, spacedim > & get_fe() const
const ComponentMask & get_nonzero_components(const unsigned int i) const
Definition: fe.h:3265
void extract_locally_relevant_dofs(const DoFHandlerType &dof_handler, IndexSet &dof_set)
Definition: dof_tools.cc:1143
void reinit(const TriaIterator< DoFCellAccessor< DoFHandlerType, lda >> cell, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int, const unsigned int fe_index=numbers::invalid_unsigned_int)
Definition: fe_values.cc:142
void compute_random(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &dof_handler)
cell_iterator end() const
Definition: dof_handler.cc:959
unsigned int first_selected_component(const unsigned int overall_number_of_components=numbers::invalid_unsigned_int) const
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:69
void compute_sort_selected_dofs_back(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &dof_handler, const std::vector< bool > &selected_dofs)
const unsigned int dofs_per_cell
Definition: fe_base.h:297
void renumber_dofs(const std::vector< types::global_dof_index > &new_numbers)
void swap(Vector< Number > &u, Vector< Number > &v)
Definition: vector.h:1353
void reinit(const IndexSet &local_constraints=IndexSet())
void extract_locally_active_dofs(const DoFHandlerType &dof_handler, IndexSet &dof_set)
Definition: dof_tools.cc:1105
cell_iterator begin(const unsigned int level=0) const
Definition: dof_handler.cc:930
cell_iterator end() const
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1443
void compute_clockwise_dg(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &dof_handler, const Point< DoFHandlerType::space_dimension > &center, const bool counter)
Definition: mpi.h:55
void king_ordering(DoFHandlerType &dof_handler, const bool reversed_numbering=false, const bool use_constraints=false)
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
Definition: fe.h:3087
void block_wise(DoFHandler< dim, spacedim > &dof_handler)
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1834
Definition: fe.h:36
void compute_Cuthill_McKee(std::vector< types::global_dof_index > &new_dof_indices, const DoFHandlerType &, const bool reversed_numbering=false, const bool use_constraints=false)
std::vector< unsigned int > reverse_permutation(const std::vector< unsigned int > &permutation)
Definition: utilities.cc:489
bool is_element(const size_type index) const
Definition: index_set.h:1676
static::ExceptionBase & ExcNotImplemented()
const ::FEValues< dim, spacedim > & get_present_fe_values() const
void subdomain_wise(DoFHandlerType &dof_handler)
typename ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:240
void clockwise_dg(DoFHandlerType &dof_handler, const Point< DoFHandlerType::space_dimension > &center, const bool counter=false)
const types::global_dof_index invalid_dof_index
Definition: types.h:188
const IndexSet & locally_owned_dofs() const
size_type nth_index_in_set(const unsigned int local_index) const
Definition: index_set.h:1793
void make_sparsity_pattern(const DoFHandlerType &dof_handler, SparsityPatternType &sparsity_pattern, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
types::global_dof_index compute_block_wise(std::vector< types::global_dof_index > &new_dof_indices, const ITERATOR &start, const ENDITERATOR &end, bool is_level_operation)
void push_back(const Quadrature< dim > &new_quadrature)
Definition: q_collection.h:194
static::ExceptionBase & ExcInternalError()
void cell_wise(DoFHandlerType &dof_handler, const std::vector< typename DoFHandlerType::active_cell_iterator > &cell_order)