Reference documentation for deal.II version 9.1.0-pre
dof_handler_policy.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 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 
17 #include <deal.II/base/geometry_info.h>
18 #include <deal.II/base/memory_consumption.h>
19 #include <deal.II/base/partitioner.h>
20 #include <deal.II/base/thread_management.h>
21 #include <deal.II/base/utilities.h>
22 #include <deal.II/base/work_stream.h>
23 
24 #include <deal.II/distributed/shared_tria.h>
25 #include <deal.II/distributed/tria.h>
26 
27 #include <deal.II/dofs/dof_accessor.h>
28 #include <deal.II/dofs/dof_handler.h>
29 #include <deal.II/dofs/dof_handler_policy.h>
30 
31 #include <deal.II/fe/fe.h>
32 
33 #include <deal.II/grid/grid_tools.h>
34 #include <deal.II/grid/tria.h>
35 #include <deal.II/grid/tria_iterator.h>
36 
37 #include <boost/archive/binary_iarchive.hpp>
38 #include <boost/archive/binary_oarchive.hpp>
39 #ifdef DEAL_II_WITH_ZLIB
40 # include <boost/iostreams/device/back_inserter.hpp>
41 # include <boost/iostreams/filter/gzip.hpp>
42 # include <boost/iostreams/filtering_stream.hpp>
43 # include <boost/iostreams/stream.hpp>
44 # include <boost/serialization/array.hpp>
45 #endif
46 
47 #include <algorithm>
48 #include <memory>
49 #include <numeric>
50 #include <set>
51 
52 DEAL_II_NAMESPACE_OPEN
53 
54 
55 namespace internal
56 {
57  namespace DoFHandlerImplementation
58  {
59  namespace Policy
60  {
61  // use class ::DoFHandler instead
62  // of namespace internal::DoFHandler in
63  // the following
64  using ::DoFHandler;
65 
66  namespace hp
67  {
68  using ::hp::DoFHandler;
69  }
70 
71 
72  namespace
73  {
78  template <class DoFHandlerType>
79  void
80  update_all_active_cell_dof_indices_caches(
81  const DoFHandlerType &dof_handler)
82  {
83  typename DoFHandlerType::active_cell_iterator
84  beginc = dof_handler.begin_active(),
85  endc = dof_handler.end();
86 
87  auto worker =
88  [](const typename DoFHandlerType::active_cell_iterator &cell,
89  void *,
90  void *) {
91  if (!cell->is_artificial())
92  cell->update_cell_dof_indices_cache();
93  };
94 
95  // parallelize filling all of the cell caches. by using
96  // WorkStream, we make sure that we only run through the
97  // range of iterators once, whereas a parallel_for loop
98  // for example has to split the range multiple times,
99  // which is expensive because cell iterators are not
100  // random access iterators with a cheap operator-
101  WorkStream::run(beginc,
102  endc,
103  worker,
104  /* copier */ std::function<void(void *)>(),
105  /* scratch_data */ nullptr,
106  /* copy_data */ nullptr,
108  /* chunk_size = */ 32);
109  }
110 
111 
116  template <class DoFHandlerType>
117  void
118  update_all_level_cell_dof_indices_caches(
119  const DoFHandlerType &dof_handler)
120  {
121  typename DoFHandlerType::level_cell_iterator beginc =
122  dof_handler.begin(),
123  endc = dof_handler.end();
124 
125  auto worker =
126  [](const typename DoFHandlerType::level_cell_iterator &cell,
127  void *,
128  void *) {
129  if (cell->has_children() || !cell->is_artificial())
130  cell->update_cell_dof_indices_cache();
131  };
132 
133  // parallelize filling all of the cell caches. by using
134  // WorkStream, we make sure that we only run through the
135  // range of iterators once, whereas a parallel_for loop
136  // for example has to split the range multiple times,
137  // which is expensive because cell iterators are not
138  // random access iterators with a cheap operator-
139  WorkStream::run(beginc,
140  endc,
141  worker,
142  /* copier */ std::function<void(void *)>(),
143  /* scratch_data */ nullptr,
144  /* copy_data */ nullptr,
146  /* chunk_size = */ 32);
147  }
148 
149 
150  using DoFIdentities =
151  std::vector<std::pair<unsigned int, unsigned int>>;
152 
153 
164  template <int structdim, int dim, int spacedim>
165  void
166  ensure_existence_of_dof_identities(
167  const FiniteElement<dim, spacedim> &fe1,
168  const FiniteElement<dim, spacedim> &fe2,
169  std::unique_ptr<DoFIdentities> & identities)
170  {
171  // see if we need to fill this entry, or whether it already
172  // exists
173  if (identities.get() == nullptr)
174  {
175  switch (structdim)
176  {
177  case 0:
178  {
179  identities = std_cxx14::make_unique<DoFIdentities>(
180  fe1.hp_vertex_dof_identities(fe2));
181  break;
182  }
183 
184  case 1:
185  {
186  identities = std_cxx14::make_unique<DoFIdentities>(
187  fe1.hp_line_dof_identities(fe2));
188  break;
189  }
190 
191  case 2:
192  {
193  identities = std_cxx14::make_unique<DoFIdentities>(
194  fe1.hp_quad_dof_identities(fe2));
195  break;
196  }
197 
198  default:
199  Assert(false, ExcNotImplemented());
200  }
201 
202  // double check whether the newly created entries make
203  // any sense at all
204  for (unsigned int i = 0; i < identities->size(); ++i)
205  {
206  Assert((*identities)[i].first <
207  fe1.template n_dofs_per_object<structdim>(),
208  ExcInternalError());
209  Assert((*identities)[i].second <
210  fe2.template n_dofs_per_object<structdim>(),
211  ExcInternalError());
212  }
213  }
214  }
215 
216 
217 
225  template <int dim, int spacedim, typename iterator>
226  unsigned int
227  get_most_dominating_fe_index(const iterator &object)
228  {
229  unsigned int dominating_fe_index = 0;
230  for (; dominating_fe_index < object->n_active_fe_indices();
231  ++dominating_fe_index)
232  {
233  const FiniteElement<dim, spacedim> &this_fe = object->get_fe(
234  object->nth_active_fe_index(dominating_fe_index));
235 
238  for (unsigned int other_fe_index = 0;
239  other_fe_index < object->n_active_fe_indices();
240  ++other_fe_index)
241  if (other_fe_index != dominating_fe_index)
242  {
243  const FiniteElement<dim, spacedim> &that_fe =
244  object->get_fe(
245  object->nth_active_fe_index(other_fe_index));
246 
247  domination =
248  domination & this_fe.compare_for_face_domination(that_fe);
249  }
250 
251  // see if this element is able to dominate all the other
252  // ones, and if so take it
253  if ((domination ==
255  (domination ==
258  break;
259  }
260 
261  // check that we have found one such fe
262  if (dominating_fe_index != object->n_active_fe_indices())
263  {
264  // return the finite element index used on it. note that
265  // only a single fe can be active on such subfaces
266  return object->nth_active_fe_index(dominating_fe_index);
267  }
268  else
269  {
270  // if we couldn't find the most dominating object
272  }
273  }
274  } // namespace
275 
276 
277 
278  struct Implementation
279  {
280  /* -------------- distribute_dofs functionality ------------- */
281 
289  template <int spacedim>
291  distribute_dofs_on_cell(
292  const DoFHandler<1, spacedim> &dof_handler,
294  types::global_dof_index next_free_dof)
295  {
296  // distribute dofs of vertices
297  if (dof_handler.get_fe().dofs_per_vertex > 0)
298  for (unsigned int v = 0; v < GeometryInfo<1>::vertices_per_cell;
299  ++v)
300  {
301  if (cell->vertex_dof_index(v, 0) == numbers::invalid_dof_index)
302  for (unsigned int d = 0;
303  d < dof_handler.get_fe().dofs_per_vertex;
304  ++d)
305  {
306  Assert((cell->vertex_dof_index(v, d) ==
308  ExcInternalError());
309  cell->set_vertex_dof_index(v, d, next_free_dof++);
310  }
311  else
312  for (unsigned int d = 0;
313  d < dof_handler.get_fe().dofs_per_vertex;
314  ++d)
315  Assert((cell->vertex_dof_index(v, d) !=
317  ExcInternalError());
318  }
319 
320  // dofs of line
321  for (unsigned int d = 0; d < dof_handler.get_fe().dofs_per_line; ++d)
322  cell->set_dof_index(d, next_free_dof++);
323 
324  return next_free_dof;
325  }
326 
327 
328 
329  template <int spacedim>
331  distribute_dofs_on_cell(
332  const DoFHandler<2, spacedim> &dof_handler,
334  types::global_dof_index next_free_dof)
335  {
336  if (dof_handler.get_fe().dofs_per_vertex > 0)
337  // number dofs on vertices
338  for (unsigned int vertex = 0;
339  vertex < GeometryInfo<2>::vertices_per_cell;
340  ++vertex)
341  // check whether dofs for this vertex have been distributed
342  // (checking the first dof should be good enough)
343  if (cell->vertex_dof_index(vertex, 0) ==
345  for (unsigned int d = 0;
346  d < dof_handler.get_fe().dofs_per_vertex;
347  ++d)
348  cell->set_vertex_dof_index(vertex, d, next_free_dof++);
349 
350  // for the four sides
351  if (dof_handler.get_fe().dofs_per_line > 0)
352  for (unsigned int side = 0; side < GeometryInfo<2>::faces_per_cell;
353  ++side)
354  {
355  const typename DoFHandler<2, spacedim>::line_iterator line =
356  cell->line(side);
357 
358  // distribute dofs if necessary: check whether line dof is
359  // already numbered (checking the first dof should be good
360  // enough)
361  if (line->dof_index(0) == numbers::invalid_dof_index)
362  // if not: distribute dofs
363  for (unsigned int d = 0;
364  d < dof_handler.get_fe().dofs_per_line;
365  ++d)
366  line->set_dof_index(d, next_free_dof++);
367  }
368 
369 
370  // dofs of quad
371  if (dof_handler.get_fe().dofs_per_quad > 0)
372  for (unsigned int d = 0; d < dof_handler.get_fe().dofs_per_quad;
373  ++d)
374  cell->set_dof_index(d, next_free_dof++);
375 
376  return next_free_dof;
377  }
378 
379 
380 
381  template <int spacedim>
383  distribute_dofs_on_cell(
384  const DoFHandler<3, spacedim> &dof_handler,
386  types::global_dof_index next_free_dof)
387  {
388  if (dof_handler.get_fe().dofs_per_vertex > 0)
389  // number dofs on vertices
390  for (unsigned int vertex = 0;
391  vertex < GeometryInfo<3>::vertices_per_cell;
392  ++vertex)
393  // check whether dofs for this vertex have been distributed
394  // (checking the first dof should be good enough)
395  if (cell->vertex_dof_index(vertex, 0) ==
397  for (unsigned int d = 0;
398  d < dof_handler.get_fe().dofs_per_vertex;
399  ++d)
400  cell->set_vertex_dof_index(vertex, d, next_free_dof++);
401 
402  // for the lines
403  if (dof_handler.get_fe().dofs_per_line > 0)
404  for (unsigned int l = 0; l < GeometryInfo<3>::lines_per_cell; ++l)
405  {
406  const typename DoFHandler<3, spacedim>::line_iterator line =
407  cell->line(l);
408 
409  // distribute dofs if necessary: check whether line dof is
410  // already numbered (checking the first dof should be good
411  // enough)
412  if (line->dof_index(0) == numbers::invalid_dof_index)
413  // if not: distribute dofs
414  for (unsigned int d = 0;
415  d < dof_handler.get_fe().dofs_per_line;
416  ++d)
417  line->set_dof_index(d, next_free_dof++);
418  }
419 
420  // for the quads
421  if (dof_handler.get_fe().dofs_per_quad > 0)
422  for (unsigned int q = 0; q < GeometryInfo<3>::quads_per_cell; ++q)
423  {
424  const typename DoFHandler<3, spacedim>::quad_iterator quad =
425  cell->quad(q);
426 
427  // distribute dofs if necessary: check whether line dof is
428  // already numbered (checking the first dof should be good
429  // enough)
430  if (quad->dof_index(0) == numbers::invalid_dof_index)
431  // if not: distribute dofs
432  for (unsigned int d = 0;
433  d < dof_handler.get_fe().dofs_per_quad;
434  ++d)
435  quad->set_dof_index(d, next_free_dof++);
436  }
437 
438 
439  // dofs of hex
440  if (dof_handler.get_fe().dofs_per_hex > 0)
441  for (unsigned int d = 0; d < dof_handler.get_fe().dofs_per_hex; ++d)
442  cell->set_dof_index(d, next_free_dof++);
443 
444  return next_free_dof;
445  }
446 
447 
448 
449  // same for the hp::DoFHandler
450  template <int spacedim>
452  distribute_dofs_on_cell(
455  & cell,
456  types::global_dof_index next_free_dof)
457  {
458  const unsigned int dim = 1;
459 
460  const FiniteElement<dim, spacedim> &fe = cell->get_fe();
461  const unsigned int fe_index = cell->active_fe_index();
462 
463  // number dofs on vertices. to do so, check whether dofs for
464  // this vertex have been distributed and for the present fe
465  // (only check the first dof), and if this isn't the case
466  // distribute new ones there
467  if (fe.dofs_per_vertex > 0)
468  for (unsigned int vertex = 0;
469  vertex < GeometryInfo<1>::vertices_per_cell;
470  ++vertex)
471  if (cell->vertex_dof_index(vertex, 0, fe_index) ==
473  for (unsigned int d = 0; d < fe.dofs_per_vertex;
474  ++d, ++next_free_dof)
475  cell->set_vertex_dof_index(vertex,
476  d,
477  next_free_dof,
478  fe_index);
479 
480  // finally for the line. this one shouldn't be numbered yet
481  if (fe.dofs_per_line > 0)
482  {
483  Assert((cell->dof_index(0, fe_index) ==
485  ExcInternalError());
486 
487  for (unsigned int d = 0; d < fe.dofs_per_line;
488  ++d, ++next_free_dof)
489  cell->set_dof_index(d, next_free_dof, fe_index);
490  }
491 
492  // note that this cell has been processed
493  cell->set_user_flag();
494 
495  return next_free_dof;
496  }
497 
498 
499 
500  template <int spacedim>
502  distribute_dofs_on_cell(
505  & cell,
506  types::global_dof_index next_free_dof)
507  {
508  const unsigned int dim = 2;
509 
510  const FiniteElement<dim, spacedim> &fe = cell->get_fe();
511  const unsigned int fe_index = cell->active_fe_index();
512 
513  // number dofs on vertices. to do so, check whether dofs for
514  // this vertex have been distributed and for the present fe
515  // (only check the first dof), and if this isn't the case
516  // distribute new ones there
517  if (fe.dofs_per_vertex > 0)
518  for (unsigned int vertex = 0;
519  vertex < GeometryInfo<2>::vertices_per_cell;
520  ++vertex)
521  if (cell->vertex_dof_index(vertex, 0, fe_index) ==
523  for (unsigned int d = 0; d < fe.dofs_per_vertex;
524  ++d, ++next_free_dof)
525  cell->set_vertex_dof_index(vertex,
526  d,
527  next_free_dof,
528  fe_index);
529 
530  // next the sides. do the same as above: check whether the
531  // line is already numbered for the present fe_index, and if
532  // not do it
533  if (fe.dofs_per_line > 0)
534  for (unsigned int l = 0; l < GeometryInfo<2>::lines_per_cell; ++l)
535  {
536  typename hp::DoFHandler<dim, spacedim>::line_iterator line =
537  cell->line(l);
538 
539  if (line->dof_index(0, fe_index) == numbers::invalid_dof_index)
540  for (unsigned int d = 0; d < fe.dofs_per_line;
541  ++d, ++next_free_dof)
542  line->set_dof_index(d, next_free_dof, fe_index);
543  }
544 
545 
546  // finally for the quad. this one shouldn't be numbered yet
547  if (fe.dofs_per_quad > 0)
548  {
549  Assert((cell->dof_index(0, fe_index) ==
551  ExcInternalError());
552 
553  for (unsigned int d = 0; d < fe.dofs_per_quad;
554  ++d, ++next_free_dof)
555  cell->set_dof_index(d, next_free_dof, fe_index);
556  }
557 
558  // note that this cell has been processed
559  cell->set_user_flag();
560 
561  return next_free_dof;
562  }
563 
564 
565 
566  template <int spacedim>
568  distribute_dofs_on_cell(
571  & cell,
572  types::global_dof_index next_free_dof)
573  {
574  const unsigned int dim = 3;
575 
576  const FiniteElement<dim, spacedim> &fe = cell->get_fe();
577  const unsigned int fe_index = cell->active_fe_index();
578 
579  // number dofs on vertices. to do so, check whether dofs for
580  // this vertex have been distributed and for the present fe
581  // (only check the first dof), and if this isn't the case
582  // distribute new ones there
583  if (fe.dofs_per_vertex > 0)
584  for (unsigned int vertex = 0;
585  vertex < GeometryInfo<3>::vertices_per_cell;
586  ++vertex)
587  if (cell->vertex_dof_index(vertex, 0, fe_index) ==
589  for (unsigned int d = 0; d < fe.dofs_per_vertex;
590  ++d, ++next_free_dof)
591  cell->set_vertex_dof_index(vertex,
592  d,
593  next_free_dof,
594  fe_index);
595 
596  // next the four lines. do the same as above: check whether
597  // the line is already numbered for the present fe_index,
598  // and if not do it
599  if (fe.dofs_per_line > 0)
600  for (unsigned int l = 0; l < GeometryInfo<3>::lines_per_cell; ++l)
601  {
602  typename hp::DoFHandler<dim, spacedim>::line_iterator line =
603  cell->line(l);
604 
605  if (line->dof_index(0, fe_index) == numbers::invalid_dof_index)
606  for (unsigned int d = 0; d < fe.dofs_per_line;
607  ++d, ++next_free_dof)
608  line->set_dof_index(d, next_free_dof, fe_index);
609  }
610 
611  // same for quads
612  if (fe.dofs_per_quad > 0)
613  for (unsigned int q = 0; q < GeometryInfo<3>::quads_per_cell; ++q)
614  {
615  typename hp::DoFHandler<dim, spacedim>::quad_iterator quad =
616  cell->quad(q);
617 
618  if (quad->dof_index(0, fe_index) == numbers::invalid_dof_index)
619  for (unsigned int d = 0; d < fe.dofs_per_quad;
620  ++d, ++next_free_dof)
621  quad->set_dof_index(d, next_free_dof, fe_index);
622  }
623 
624 
625  // finally for the hex. this one shouldn't be numbered yet
626  if (fe.dofs_per_hex > 0)
627  {
628  Assert((cell->dof_index(0, fe_index) ==
630  ExcInternalError());
631 
632  for (unsigned int d = 0; d < fe.dofs_per_hex;
633  ++d, ++next_free_dof)
634  cell->set_dof_index(d, next_free_dof, fe_index);
635  }
636 
637  // note that this cell has been processed
638  cell->set_user_flag();
639 
640  return next_free_dof;
641  }
642 
643 
644 
649  template <int dim, int spacedim>
650  static std::map<types::global_dof_index, types::global_dof_index>
651  compute_vertex_dof_identities(
652  hp::DoFHandler<dim, spacedim> &dof_handler)
653  {
654  std::map<types::global_dof_index, types::global_dof_index>
655  dof_identities;
656 
657  // Note: we may wish to have something here similar to what
658  // we do for lines and quads, namely that we only identify
659  // dofs for any fe towards the most dominating one. however,
660  // it is not clear whether this is actually necessary for
661  // vertices at all, I can't think of a finite element that
662  // would make that necessary...
664  vertex_dof_identities(dof_handler.get_fe_collection().size(),
665  dof_handler.get_fe_collection().size());
666 
667  // first identify vertices we want to exclude from working on.
668  // specifically, these are the vertices of artificial and ghost
669  // cells because at the time when we get here, we do not yet
670  // know DoF indices on ghost cells (and we will never know
671  // them for artificial cells). this is, at least the case for
672  // parallel::distributed::Triangulations.
673  //
674  // this means that we will not unify DoF indices between locally
675  // owned cells and ghost cells, and this is different from what
676  // we would do if the triangulation were not split into subdomains.
677  // on the other hand, DoF unification is only an optimization: we
678  // will still record these identities when we compute hanging
679  // node constraints; we just end up with more DoFs than we would
680  // if we unified DoF indices also between locally owned and ghost
681  // cells, but we end up with a simpler algorithm in return.
682  std::vector<bool> include_vertex =
683  dof_handler.get_triangulation().get_used_vertices();
684  if (dynamic_cast<
686  &dof_handler.get_triangulation()) != nullptr)
687  for (const auto &cell : dof_handler.active_cell_iterators())
688  if (!cell->is_locally_owned())
689  for (unsigned int v = 0;
690  v < GeometryInfo<dim>::vertices_per_cell;
691  ++v)
692  include_vertex[cell->vertex_index(v)] = false;
693 
694  // loop over all vertices and see which one we need to work
695  // on
696  for (unsigned int vertex_index = 0;
697  vertex_index < dof_handler.get_triangulation().n_vertices();
698  ++vertex_index)
699  if ((dof_handler.get_triangulation()
700  .get_used_vertices()[vertex_index] == true) &&
701  (include_vertex[vertex_index] == true))
702  {
703  const unsigned int n_active_fe_indices =
704  ::internal::DoFAccessorImplementation::Implementation::
705  n_active_vertex_fe_indices(dof_handler, vertex_index);
706  if (n_active_fe_indices > 1)
707  {
708  const unsigned int first_fe_index =
709  ::internal::DoFAccessorImplementation::
710  Implementation::nth_active_vertex_fe_index(dof_handler,
711  vertex_index,
712  0);
713 
714  // loop over all the other FEs with which we want
715  // to identify the DoF indices of the first FE of
716  for (unsigned int f = 1; f < n_active_fe_indices; ++f)
717  {
718  const unsigned int other_fe_index =
719  ::internal::DoFAccessorImplementation::
720  Implementation::nth_active_vertex_fe_index(
721  dof_handler, vertex_index, f);
722 
723  // make sure the entry in the equivalence
724  // table exists
725  ensure_existence_of_dof_identities<0>(
726  dof_handler.get_fe(first_fe_index),
727  dof_handler.get_fe(other_fe_index),
728  vertex_dof_identities[first_fe_index]
729  [other_fe_index]);
730 
731  // then loop through the identities we
732  // have. first get the global numbers of the
733  // dofs we want to identify and make sure they
734  // are not yet constrained to anything else,
735  // except for to each other. use the rule that
736  // we will always constrain the dof with the
737  // higher fe index to the one with the lower,
738  // to avoid circular reasoning.
739  DoFIdentities &identities =
740  *vertex_dof_identities[first_fe_index]
741  [other_fe_index];
742  for (unsigned int i = 0; i < identities.size(); ++i)
743  {
744  const types::global_dof_index lower_dof_index =
745  ::internal::DoFAccessorImplementation::
746  Implementation::get_vertex_dof_index(
747  dof_handler,
748  vertex_index,
749  first_fe_index,
750  identities[i].first);
751  const types::global_dof_index higher_dof_index =
752  ::internal::DoFAccessorImplementation::
753  Implementation::get_vertex_dof_index(
754  dof_handler,
755  vertex_index,
756  other_fe_index,
757  identities[i].second);
758 
759  Assert((dof_identities.find(higher_dof_index) ==
760  dof_identities.end()) ||
761  (dof_identities[higher_dof_index] ==
762  lower_dof_index),
763  ExcInternalError());
764 
765  dof_identities[higher_dof_index] = lower_dof_index;
766  }
767  }
768  }
769  }
770 
771  return dof_identities;
772  }
773 
774 
779  template <int spacedim>
780  static std::map<types::global_dof_index, types::global_dof_index>
781  compute_line_dof_identities(hp::DoFHandler<1, spacedim> &)
782  {
783  return std::map<types::global_dof_index, types::global_dof_index>();
784  }
785 
786 
787  template <int dim, int spacedim>
788  static std::map<types::global_dof_index, types::global_dof_index>
789  compute_line_dof_identities(hp::DoFHandler<dim, spacedim> &dof_handler)
790  {
791  std::map<types::global_dof_index, types::global_dof_index>
792  dof_identities;
793 
794  // we will mark lines that we have already treated, so first save and
795  // clear the user flags on lines and later restore them
796  std::vector<bool> user_flags;
797  dof_handler.get_triangulation().save_user_flags_line(user_flags);
798  const_cast<::Triangulation<dim, spacedim> &>(
799  dof_handler.get_triangulation())
800  .clear_user_flags_line();
801 
802  // exclude lines that bound cells we don't locally own, because
803  // we do not have information about their dofs at this point.
804  // this is, at least the case for
805  // parallel::distributed::Triangulations.
806  //
807  // this means that we will not unify DoF indices between locally
808  // owned cells and ghost cells, and this is different from what
809  // we would do if the triangulation were not split into subdomains.
810  // on the other hand, DoF unification is only an optimization: we
811  // will still record these identities when we compute hanging
812  // node constraints; we just end up with more DoFs than we would
813  // if we unified DoF indices also between locally owned and ghost
814  // cells, but we end up with a simpler algorithm in return.
815  if (dynamic_cast<
817  &dof_handler.get_triangulation()) != nullptr)
819  cell = dof_handler.begin_active();
820  cell != dof_handler.end();
821  ++cell)
822  if (cell->is_locally_owned() == false)
823  for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell;
824  ++l)
825  cell->line(l)->set_user_flag();
826 
827  // An implementation of the algorithm described in the hp paper,
828  // including the modification mentioned later in the "complications in
829  // 3-d" subsections
830  //
831  // as explained there, we do something only if there are exactly 2
832  // finite elements associated with an object. if there is only one,
833  // then there is nothing to do anyway, and if there are 3 or more,
834  // then we can get into trouble. note that this only happens for lines
835  // in 3d and higher, and for quads only in 4d and higher, so this
836  // isn't a particularly frequent case
837  //
838  // there is one case, however, that we would like to handle (see, for
839  // example, the hp/crash_15 testcase): if we have
840  // FESystem(FE_Q(2),FE_DGQ(i)) elements for a bunch of values 'i',
841  // then we should be able to handle this because we can simply unify
842  // *all* dofs, not only a some. so what we do is to first treat all
843  // pairs of finite elements that have *identical* dofs, and then only
844  // deal with those that are not identical of which we can handle at
845  // most 2
846  ::Table<2, std::unique_ptr<DoFIdentities>> line_dof_identities(
847  dof_handler.fe_collection.size(), dof_handler.fe_collection.size());
848 
850  cell = dof_handler.begin_active();
851  cell != dof_handler.end();
852  ++cell)
853  for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell; ++l)
854  if (cell->line(l)->user_flag_set() == false)
855  {
856  const typename hp::DoFHandler<dim, spacedim>::line_iterator
857  line = cell->line(l);
858  line->set_user_flag();
859 
860  unsigned int unique_sets_of_dofs =
861  line->n_active_fe_indices();
862 
863  // do a first loop over all sets of dofs and do identity
864  // uniquification
865  const unsigned int n_active_fe_indices =
866  line->n_active_fe_indices();
867  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
868  for (unsigned int g = f + 1; g < n_active_fe_indices; ++g)
869  {
870  const unsigned int fe_index_1 =
871  line->nth_active_fe_index(f),
872  fe_index_2 =
873  line->nth_active_fe_index(g);
874 
875  if ((dof_handler.get_fe(fe_index_1).dofs_per_line ==
876  dof_handler.get_fe(fe_index_2).dofs_per_line) &&
877  (dof_handler.get_fe(fe_index_1).dofs_per_line > 0))
878  {
879  ensure_existence_of_dof_identities<1>(
880  dof_handler.get_fe(fe_index_1),
881  dof_handler.get_fe(fe_index_2),
882  line_dof_identities[fe_index_1][fe_index_2]);
883  // see if these sets of dofs are identical. the
884  // first condition for this is that indeed there are
885  // n identities
886  if (line_dof_identities[fe_index_1][fe_index_2]
887  ->size() ==
888  dof_handler.get_fe(fe_index_1).dofs_per_line)
889  {
890  unsigned int i = 0;
891  for (; i < dof_handler.get_fe(fe_index_1)
892  .dofs_per_line;
893  ++i)
894  if (((*(line_dof_identities[fe_index_1]
895  [fe_index_2]))[i]
896  .first != i) &&
897  ((*(line_dof_identities[fe_index_1]
898  [fe_index_2]))[i]
899  .second != i))
900  // not an identity
901  break;
902 
903  if (i == dof_handler.get_fe(fe_index_1)
904  .dofs_per_line)
905  {
906  // The line dofs (i.e., the ones interior to
907  // a line) of these two finite elements are
908  // identical. Note that there could be
909  // situations when one element still
910  // dominates another, e.g.: FE_Q(2) x
911  // FE_Nothing(dominate) vs FE_Q(2) x FE_Q(1)
912 
913  --unique_sets_of_dofs;
914 
915  for (unsigned int j = 0;
916  j < dof_handler.get_fe(fe_index_1)
917  .dofs_per_line;
918  ++j)
919  {
921  master_dof_index =
922  line->dof_index(j, fe_index_1);
924  slave_dof_index =
925  line->dof_index(j, fe_index_2);
926 
927  // if master dof was already
928  // constrained, constrain to that one,
929  // otherwise constrain slave to master
930  if (dof_identities.find(
931  master_dof_index) !=
932  dof_identities.end())
933  {
934  Assert(dof_identities.find(
935  dof_identities
936  [master_dof_index]) ==
937  dof_identities.end(),
938  ExcInternalError());
939 
940  dof_identities[slave_dof_index] =
941  dof_identities[master_dof_index];
942  }
943  else
944  {
945  Assert((dof_identities.find(
946  master_dof_index) ==
947  dof_identities.end()) ||
948  (dof_identities
949  [slave_dof_index] ==
950  master_dof_index),
951  ExcInternalError());
952 
953  dof_identities[slave_dof_index] =
954  master_dof_index;
955  }
956  }
957  }
958  }
959  }
960  }
961 
962  // if at this point, there is only one unique set of dofs
963  // left, then we have taken care of everything above. if there
964  // are two, then we need to deal with them here. if there are
965  // more, then we punt, as described in the paper (and
966  // mentioned above)
967  // TODO: The check for 'dim==2' was inserted by intuition. It
968  // fixes
969  // the previous problems with @ref step_27 "step-27" in 3D. But an
970  // explanation for this is still required, and what we do here
971  // is not what we describe in the paper!.
972  if ((unique_sets_of_dofs == 2) && (dim == 2))
973  {
974  // find out which is the most dominating finite element of
975  // the ones that are used on this line
976  const unsigned int most_dominating_fe_index =
977  get_most_dominating_fe_index<dim, spacedim>(line);
978 
979  // if we found the most dominating element, then use this
980  // to eliminate some of the degrees of freedom by
981  // identification. otherwise, the code that computes
982  // hanging node constraints will have to deal with it by
983  // computing appropriate constraints along this face/edge
984  if (most_dominating_fe_index !=
986  {
987  const unsigned int n_active_fe_indices =
988  line->n_active_fe_indices();
989 
990  // loop over the indices of all the finite elements
991  // that are not dominating, and identify their dofs to
992  // the most dominating one
993  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
994  if (line->nth_active_fe_index(f) !=
995  most_dominating_fe_index)
996  {
997  const unsigned int other_fe_index =
998  line->nth_active_fe_index(f);
999 
1000  ensure_existence_of_dof_identities<1>(
1001  dof_handler.get_fe(most_dominating_fe_index),
1002  dof_handler.get_fe(other_fe_index),
1003  line_dof_identities[most_dominating_fe_index]
1004  [other_fe_index]);
1005 
1006  DoFIdentities &identities =
1007  *line_dof_identities[most_dominating_fe_index]
1008  [other_fe_index];
1009  for (unsigned int i = 0; i < identities.size();
1010  ++i)
1011  {
1013  master_dof_index = line->dof_index(
1014  identities[i].first,
1015  most_dominating_fe_index);
1017  slave_dof_index =
1018  line->dof_index(identities[i].second,
1019  other_fe_index);
1020 
1021  Assert((dof_identities.find(
1022  master_dof_index) ==
1023  dof_identities.end()) ||
1024  (dof_identities[slave_dof_index] ==
1025  master_dof_index),
1026  ExcInternalError());
1027 
1028  dof_identities[slave_dof_index] =
1029  master_dof_index;
1030  }
1031  }
1032  }
1033  }
1034  }
1035 
1036  // finally restore the user flags
1037  const_cast<::Triangulation<dim, spacedim> &>(
1038  dof_handler.get_triangulation())
1039  .load_user_flags_line(user_flags);
1040 
1041  return dof_identities;
1042  }
1043 
1044 
1045 
1050  template <int dim, int spacedim>
1051  static std::map<types::global_dof_index, types::global_dof_index>
1052  compute_quad_dof_identities(hp::DoFHandler<dim, spacedim> &)
1053  {
1054  // this function should only be called for dim<3 where there are
1055  // no quad dof identies. for dim>=3, the specialization below should
1056  // take care of it
1057  Assert(dim < 3, ExcInternalError());
1058 
1059  return std::map<types::global_dof_index, types::global_dof_index>();
1060  }
1061 
1062 
1063  template <int spacedim>
1064  static std::map<types::global_dof_index, types::global_dof_index>
1065  compute_quad_dof_identities(hp::DoFHandler<3, spacedim> &dof_handler)
1066  {
1067  const int dim = 3;
1068 
1069  std::map<types::global_dof_index, types::global_dof_index>
1070  dof_identities;
1071 
1072 
1073  // we will mark quads that we have already treated, so first
1074  // save and clear the user flags on quads and later restore
1075  // them
1076  std::vector<bool> user_flags;
1077  dof_handler.get_triangulation().save_user_flags_quad(user_flags);
1078  const_cast<::Triangulation<dim, spacedim> &>(
1079  dof_handler.get_triangulation())
1080  .clear_user_flags_quad();
1081 
1082  // exclude quads that bound cells we don't locally own, because
1083  // we do not have information about their dofs at this point.
1084  // this is, at least the case for
1085  // parallel::distributed::Triangulations.
1086  //
1087  // this means that we will not unify DoF indices between locally
1088  // owned cells and ghost cells, and this is different from what
1089  // we would do if the triangulation were not split into subdomains.
1090  // on the other hand, DoF unification is only an optimization: we
1091  // will still record these identities when we compute hanging
1092  // node constraints; we just end up with more DoFs than we would
1093  // if we unified DoF indices also between locally owned and ghost
1094  // cells, but we end up with a simpler algorithm in return.
1095  if (dynamic_cast<
1097  &dof_handler.get_triangulation()) != nullptr)
1099  cell = dof_handler.begin_active();
1100  cell != dof_handler.end();
1101  ++cell)
1102  if (cell->is_locally_owned() == false)
1103  for (unsigned int q = 0; q < GeometryInfo<dim>::quads_per_cell;
1104  ++q)
1105  cell->quad(q)->set_user_flag();
1106 
1107 
1108  // An implementation of the algorithm described in the hp
1109  // paper, including the modification mentioned later in the
1110  // "complications in 3-d" subsections
1111  //
1112  // as explained there, we do something only if there are
1113  // exactly 2 finite elements associated with an object. if
1114  // there is only one, then there is nothing to do anyway,
1115  // and if there are 3 or more, then we can get into
1116  // trouble. note that this only happens for lines in 3d and
1117  // higher, and for quads only in 4d and higher, so this
1118  // isn't a particularly frequent case
1119  ::Table<2, std::unique_ptr<DoFIdentities>> quad_dof_identities(
1120  dof_handler.fe_collection.size(), dof_handler.fe_collection.size());
1121 
1123  cell = dof_handler.begin_active();
1124  cell != dof_handler.end();
1125  ++cell)
1126  for (unsigned int q = 0; q < GeometryInfo<dim>::quads_per_cell; ++q)
1127  if ((cell->quad(q)->user_flag_set() == false) &&
1128  (cell->quad(q)->n_active_fe_indices() == 2))
1129  {
1130  const typename hp::DoFHandler<dim, spacedim>::quad_iterator
1131  quad = cell->quad(q);
1132  quad->set_user_flag();
1133 
1134  // find out which is the most dominating finite
1135  // element of the ones that are used on this quad
1136  const unsigned int most_dominating_fe_index =
1137  get_most_dominating_fe_index<dim, spacedim>(quad);
1138 
1139  // if we found the most dominating element, then use
1140  // this to eliminate some of the degrees of freedom
1141  // by identification. otherwise, the code that
1142  // computes hanging node constraints will have to
1143  // deal with it by computing appropriate constraints
1144  // along this face/edge
1145  if (most_dominating_fe_index != numbers::invalid_unsigned_int)
1146  {
1147  const unsigned int n_active_fe_indices =
1148  quad->n_active_fe_indices();
1149 
1150  // loop over the indices of all the finite
1151  // elements that are not dominating, and
1152  // identify their dofs to the most dominating
1153  // one
1154  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
1155  if (quad->nth_active_fe_index(f) !=
1156  most_dominating_fe_index)
1157  {
1158  const unsigned int other_fe_index =
1159  quad->nth_active_fe_index(f);
1160 
1161  ensure_existence_of_dof_identities<2>(
1162  dof_handler.get_fe(most_dominating_fe_index),
1163  dof_handler.get_fe(other_fe_index),
1164  quad_dof_identities[most_dominating_fe_index]
1165  [other_fe_index]);
1166 
1167  DoFIdentities &identities =
1168  *quad_dof_identities[most_dominating_fe_index]
1169  [other_fe_index];
1170  for (unsigned int i = 0; i < identities.size(); ++i)
1171  {
1172  const types::global_dof_index master_dof_index =
1173  quad->dof_index(identities[i].first,
1174  most_dominating_fe_index);
1175  const types::global_dof_index slave_dof_index =
1176  quad->dof_index(identities[i].second,
1177  other_fe_index);
1178 
1179  Assert((dof_identities.find(master_dof_index) ==
1180  dof_identities.end()) ||
1181  (dof_identities[slave_dof_index] ==
1182  master_dof_index),
1183  ExcInternalError());
1184 
1185  dof_identities[slave_dof_index] =
1186  master_dof_index;
1187  }
1188  }
1189  }
1190  }
1191 
1192  // finally restore the user flags
1193  const_cast<::Triangulation<dim, spacedim> &>(
1194  dof_handler.get_triangulation())
1195  .load_user_flags_quad(user_flags);
1196 
1197  return dof_identities;
1198  }
1199 
1200 
1201 
1211  template <int dim, int spacedim>
1212  static unsigned int
1213  unify_dof_indices(const DoFHandler<dim, spacedim> &,
1214  const unsigned int n_dofs_before_identification,
1215  const bool)
1216  {
1217  return n_dofs_before_identification;
1218  }
1219 
1220 
1221 
1222  template <int dim, int spacedim>
1223  static unsigned int
1224  unify_dof_indices(hp::DoFHandler<dim, spacedim> &dof_handler,
1225  const unsigned int n_dofs_before_identification,
1226  const bool check_validity)
1227  {
1228  // compute the constraints that correspond to unifying
1229  // dof indices on vertices, lines, and quads. do so
1230  // in parallel
1231  std::map<types::global_dof_index, types::global_dof_index>
1232  all_constrained_indices[dim];
1233 
1234  {
1235  Threads::TaskGroup<> tasks;
1236 
1237  unsigned int i = 0;
1238  tasks += Threads::new_task([&, i]() {
1239  all_constrained_indices[i] =
1240  compute_vertex_dof_identities(dof_handler);
1241  });
1242 
1243  if (dim > 1)
1244  {
1245  ++i;
1246  tasks += Threads::new_task([&, i]() {
1247  all_constrained_indices[i] =
1248  compute_line_dof_identities(dof_handler);
1249  });
1250  }
1251 
1252  if (dim > 2)
1253  {
1254  ++i;
1255  tasks += Threads::new_task([&, i]() {
1256  all_constrained_indices[i] =
1257  compute_quad_dof_identities(dof_handler);
1258  });
1259  }
1260 
1261  tasks.join_all();
1262  }
1263 
1264  // create a vector that contains the new DoF indices; first preset the
1265  // ones that are identities as determined above, then enumerate the
1266  // rest
1267  std::vector<types::global_dof_index> new_dof_indices(
1268  n_dofs_before_identification, numbers::invalid_dof_index);
1269 
1270  for (const auto &constrained_dof_indices : all_constrained_indices)
1271  for (const auto &p : constrained_dof_indices)
1272  {
1273  Assert(new_dof_indices[p.first] == numbers::invalid_dof_index,
1274  ExcInternalError());
1275  new_dof_indices[p.first] = p.second;
1276  }
1277 
1278  types::global_dof_index next_free_dof = 0;
1279  for (types::global_dof_index i = 0; i < n_dofs_before_identification;
1280  ++i)
1281  if (new_dof_indices[i] == numbers::invalid_dof_index)
1282  {
1283  new_dof_indices[i] = next_free_dof;
1284  ++next_free_dof;
1285  }
1286 
1287  // then loop over all those that are constrained and record the
1288  // new dof number for those:
1289  for (const auto &constrained_dof_indices : all_constrained_indices)
1290  for (const auto &p : constrained_dof_indices)
1291  {
1292  Assert(new_dof_indices[p.first] != numbers::invalid_dof_index,
1293  ExcInternalError());
1294 
1295  new_dof_indices[p.first] = new_dof_indices[p.second];
1296  }
1297 
1298  for (types::global_dof_index i = 0; i < n_dofs_before_identification;
1299  ++i)
1300  {
1301  Assert(new_dof_indices[i] != numbers::invalid_dof_index,
1302  ExcInternalError());
1303  Assert(new_dof_indices[i] < next_free_dof, ExcInternalError());
1304  }
1305 
1306  // finally, do the renumbering. verify that previous dof indices
1307  // were indeed all valid on all cells that we touch if we were
1308  // told to do so
1309  renumber_dofs(new_dof_indices,
1310  IndexSet(0),
1311  dof_handler,
1312  check_validity);
1313 
1314 
1315  return next_free_dof;
1316  }
1317 
1318 
1319 
1326  template <class DoFHandlerType>
1328  distribute_dofs(const types::subdomain_id subdomain_id,
1329  DoFHandlerType & dof_handler)
1330  {
1331  Assert(dof_handler.get_triangulation().n_levels() > 0,
1332  ExcMessage("Empty triangulation"));
1333 
1334  // Step 1: distribute dofs on all cells, but definitely
1335  // exclude artificial cells
1336  types::global_dof_index next_free_dof = 0;
1337  typename DoFHandlerType::active_cell_iterator
1338  cell = dof_handler.begin_active(),
1339  endc = dof_handler.end();
1340 
1341  for (; cell != endc; ++cell)
1342  if (!cell->is_artificial())
1343  if ((subdomain_id == numbers::invalid_subdomain_id) ||
1344  (cell->subdomain_id() == subdomain_id))
1345  next_free_dof =
1346  Implementation::distribute_dofs_on_cell(dof_handler,
1347  cell,
1348  next_free_dof);
1349 
1350  // Step 2: unify dof indices in case this is an hp DoFHandler
1351  //
1352  // during unification, we need to renumber DoF indices. there,
1353  // we can check that all previous DoF indices were valid, but
1354  // this only makes sense if we really distributed DoFs on
1355  // all (non-artificial) cells above
1356  next_free_dof =
1357  unify_dof_indices(dof_handler,
1358  next_free_dof,
1359  /* check_validity = */
1360  (subdomain_id == numbers::invalid_subdomain_id));
1361 
1362  update_all_active_cell_dof_indices_caches(dof_handler);
1363 
1364  return next_free_dof;
1365  }
1366 
1367 
1368 
1369  /* -------------- distribute_mg_dofs functionality ------------- */
1370 
1371 
1379  template <int dim, int spacedim>
1381  distribute_mg_dofs_on_cell(
1382  const typename DoFHandler<dim, spacedim>::level_cell_iterator &cell,
1383  types::global_dof_index next_free_dof,
1384  const std::integral_constant<int, 1> &)
1385  {
1386  // distribute dofs of vertices
1387  if (cell->get_fe().dofs_per_vertex > 0)
1388  for (unsigned int v = 0; v < GeometryInfo<1>::vertices_per_cell;
1389  ++v)
1390  {
1391  typename DoFHandler<dim, spacedim>::level_cell_iterator
1392  neighbor = cell->neighbor(v);
1393 
1394  if (neighbor.state() == IteratorState::valid)
1395  {
1396  // has neighbor already been processed?
1397  if (neighbor->user_flag_set() &&
1398  (neighbor->level() == cell->level()))
1399  // copy dofs if the neighbor is on the same level (only
1400  // then are mg dofs the same)
1401  {
1402  if (v == 0)
1403  for (unsigned int d = 0;
1404  d < cell->get_fe().dofs_per_vertex;
1405  ++d)
1406  cell->set_mg_vertex_dof_index(
1407  cell->level(),
1408  0,
1409  d,
1410  neighbor->mg_vertex_dof_index(cell->level(),
1411  1,
1412  d));
1413  else
1414  for (unsigned int d = 0;
1415  d < cell->get_fe().dofs_per_vertex;
1416  ++d)
1417  cell->set_mg_vertex_dof_index(
1418  cell->level(),
1419  1,
1420  d,
1421  neighbor->mg_vertex_dof_index(cell->level(),
1422  0,
1423  d));
1424 
1425  // next neighbor
1426  continue;
1427  }
1428  }
1429 
1430  // otherwise: create dofs newly
1431  for (unsigned int d = 0; d < cell->get_fe().dofs_per_vertex;
1432  ++d)
1433  cell->set_mg_vertex_dof_index(cell->level(),
1434  v,
1435  d,
1436  next_free_dof++);
1437  }
1438 
1439  // dofs of line
1440  if (cell->get_fe().dofs_per_line > 0)
1441  for (unsigned int d = 0; d < cell->get_fe().dofs_per_line; ++d)
1442  cell->set_mg_dof_index(cell->level(), d, next_free_dof++);
1443 
1444  // note that this cell has been processed
1445  cell->set_user_flag();
1446 
1447  return next_free_dof;
1448  }
1449 
1450 
1451 
1452  template <int dim, int spacedim>
1454  distribute_mg_dofs_on_cell(
1455  const typename DoFHandler<dim, spacedim>::level_cell_iterator &cell,
1456  types::global_dof_index next_free_dof,
1457  const std::integral_constant<int, 2> &)
1458  {
1459  if (cell->get_fe().dofs_per_vertex > 0)
1460  // number dofs on vertices
1461  for (unsigned int vertex = 0;
1462  vertex < GeometryInfo<2>::vertices_per_cell;
1463  ++vertex)
1464  // check whether dofs for this
1465  // vertex have been distributed
1466  // (only check the first dof)
1467  if (cell->mg_vertex_dof_index(cell->level(), vertex, 0) ==
1469  for (unsigned int d = 0; d < cell->get_fe().dofs_per_vertex;
1470  ++d)
1471  cell->set_mg_vertex_dof_index(cell->level(),
1472  vertex,
1473  d,
1474  next_free_dof++);
1475 
1476  // for the four sides
1477  if (cell->get_fe().dofs_per_line > 0)
1478  for (unsigned int side = 0; side < GeometryInfo<2>::faces_per_cell;
1479  ++side)
1480  {
1481  typename DoFHandler<dim, spacedim>::line_iterator line =
1482  cell->line(side);
1483 
1484  // distribute dofs if necessary: check whether line dof is
1485  // already numbered (check only first dof)
1486  if (line->mg_dof_index(cell->level(), 0) ==
1488  // if not: distribute dofs
1489  for (unsigned int d = 0; d < cell->get_fe().dofs_per_line;
1490  ++d)
1491  line->set_mg_dof_index(cell->level(), d, next_free_dof++);
1492  }
1493 
1494 
1495  // dofs of quad
1496  if (cell->get_fe().dofs_per_quad > 0)
1497  for (unsigned int d = 0; d < cell->get_fe().dofs_per_quad; ++d)
1498  cell->set_mg_dof_index(cell->level(), d, next_free_dof++);
1499 
1500 
1501  // note that this cell has been processed
1502  cell->set_user_flag();
1503 
1504  return next_free_dof;
1505  }
1506 
1507 
1508 
1509  template <int dim, int spacedim>
1511  distribute_mg_dofs_on_cell(
1512  const typename DoFHandler<dim, spacedim>::level_cell_iterator &cell,
1513  types::global_dof_index next_free_dof,
1514  const std::integral_constant<int, 3> &)
1515  {
1516  if (cell->get_fe().dofs_per_vertex > 0)
1517  // number dofs on vertices
1518  for (unsigned int vertex = 0;
1519  vertex < GeometryInfo<3>::vertices_per_cell;
1520  ++vertex)
1521  // check whether dofs for this vertex have been distributed
1522  // (only check the first dof)
1523  if (cell->mg_vertex_dof_index(cell->level(), vertex, 0) ==
1525  for (unsigned int d = 0; d < cell->get_fe().dofs_per_vertex;
1526  ++d)
1527  cell->set_mg_vertex_dof_index(cell->level(),
1528  vertex,
1529  d,
1530  next_free_dof++);
1531 
1532  // for the lines
1533  if (cell->get_fe().dofs_per_line > 0)
1534  for (unsigned int l = 0; l < GeometryInfo<3>::lines_per_cell; ++l)
1535  {
1536  typename DoFHandler<dim, spacedim>::line_iterator line =
1537  cell->line(l);
1538 
1539  // distribute dofs if necessary:
1540  // check whether line dof is already
1541  // numbered (check only first dof)
1542  if (line->mg_dof_index(cell->level(), 0) ==
1544  // if not: distribute dofs
1545  for (unsigned int d = 0; d < cell->get_fe().dofs_per_line;
1546  ++d)
1547  line->set_mg_dof_index(cell->level(), d, next_free_dof++);
1548  }
1549 
1550  // for the quads
1551  if (cell->get_fe().dofs_per_quad > 0)
1552  for (unsigned int q = 0; q < GeometryInfo<3>::quads_per_cell; ++q)
1553  {
1554  typename DoFHandler<dim, spacedim>::quad_iterator quad =
1555  cell->quad(q);
1556 
1557  // distribute dofs if necessary:
1558  // check whether line dof is already
1559  // numbered (check only first dof)
1560  if (quad->mg_dof_index(cell->level(), 0) ==
1562  // if not: distribute dofs
1563  for (unsigned int d = 0; d < cell->get_fe().dofs_per_quad;
1564  ++d)
1565  quad->set_mg_dof_index(cell->level(), d, next_free_dof++);
1566  }
1567 
1568 
1569  // dofs of cell
1570  if (cell->get_fe().dofs_per_hex > 0)
1571  for (unsigned int d = 0; d < cell->get_fe().dofs_per_hex; ++d)
1572  cell->set_mg_dof_index(cell->level(), d, next_free_dof++);
1573 
1574 
1575  // note that this cell has been processed
1576  cell->set_user_flag();
1577 
1578  return next_free_dof;
1579  }
1580 
1581 
1582 
1583  // same for the hp::DoFHandler
1584  template <int spacedim>
1586  distribute_mg_dofs_on_cell(
1587  const hp::DoFHandler<1, spacedim> &dof_handler,
1589  & cell,
1590  types::global_dof_index next_free_dof)
1591  {
1592  (void)dof_handler;
1593  (void)cell;
1594  (void)next_free_dof;
1595  return 0;
1596  }
1597 
1598 
1599 
1600  template <int spacedim>
1602  distribute_mg_dofs_on_cell(
1603  const hp::DoFHandler<2, spacedim> &dof_handler,
1605  & cell,
1606  types::global_dof_index next_free_dof)
1607  {
1608  (void)dof_handler;
1609  (void)cell;
1610  (void)next_free_dof;
1611  return 0;
1612  }
1613 
1614 
1615 
1616  template <int spacedim>
1618  distribute_mg_dofs_on_cell(
1619  const hp::DoFHandler<3, spacedim> &dof_handler,
1621  & cell,
1622  types::global_dof_index next_free_dof)
1623  {
1624  (void)dof_handler;
1625  (void)cell;
1626  (void)next_free_dof;
1627  return 0;
1628  }
1629 
1630 
1631 
1632  template <class DoFHandlerType>
1634  distribute_dofs_on_level(const types::subdomain_id level_subdomain_id,
1635  DoFHandlerType & dof_handler,
1636  const unsigned int level)
1637  {
1638  const unsigned int dim = DoFHandlerType::dimension;
1639  const unsigned int spacedim = DoFHandlerType::space_dimension;
1640 
1641  const ::Triangulation<dim, spacedim> &tria =
1642  dof_handler.get_triangulation();
1643  Assert(tria.n_levels() > 0, ExcMessage("Empty triangulation"));
1644  if (level >= tria.n_levels())
1645  return 0; // this is allowed for multigrid
1646 
1647  // Clear user flags because we will need them. But first we save
1648  // them and make sure that we restore them later such that at
1649  // the end of this function the Triangulation will be in the
1650  // same state as it was at the beginning of this function.
1651  std::vector<bool> user_flags;
1652  tria.save_user_flags(user_flags);
1653  const_cast<::Triangulation<dim, spacedim> &>(tria)
1654  .clear_user_flags();
1655 
1656  types::global_dof_index next_free_dof = 0;
1657  typename DoFHandler<dim, spacedim>::level_cell_iterator
1658  cell = dof_handler.begin(level),
1659  endc = dof_handler.end(level);
1660 
1661  for (; cell != endc; ++cell)
1662  if ((level_subdomain_id == numbers::invalid_subdomain_id) ||
1663  (cell->level_subdomain_id() == level_subdomain_id))
1664  next_free_dof =
1665  Implementation::distribute_mg_dofs_on_cell<dim, spacedim>(
1666  cell, next_free_dof, std::integral_constant<int, dim>());
1667 
1668  // finally restore the user flags
1669  const_cast<::Triangulation<dim, spacedim> &>(tria)
1670  .load_user_flags(user_flags);
1671 
1672  return next_free_dof;
1673  }
1674 
1675 
1676 
1677  /* --------------------- renumber_dofs functionality ---------------- */
1678 
1679 
1687  template <int dim, int spacedim>
1688  static void
1689  renumber_vertex_dofs(
1690  const std::vector<types::global_dof_index> &new_numbers,
1691  const IndexSet & indices,
1692  DoFHandler<dim, spacedim> & dof_handler,
1693  const bool check_validity)
1694  {
1695  // we can not use cell iterators in this function since then
1696  // we would renumber the dofs on the interface of two cells
1697  // more than once. Anyway, this way it's not only more
1698  // correct but also faster; note, however, that dof numbers
1699  // may be invalid_dof_index, namely when the appropriate
1700  // vertex/line/etc is unused
1701  for (std::vector<types::global_dof_index>::iterator i =
1702  dof_handler.vertex_dofs.begin();
1703  i != dof_handler.vertex_dofs.end();
1704  ++i)
1705  if (*i != numbers::invalid_dof_index)
1706  *i = (indices.size() == 0) ?
1707  (new_numbers[*i]) :
1708  (new_numbers[indices.index_within_set(*i)]);
1709  else if (check_validity)
1710  // if index is invalid_dof_index: check if this one
1711  // really is unused
1712  Assert(dof_handler.get_triangulation().vertex_used(
1713  (i - dof_handler.vertex_dofs.begin()) /
1714  dof_handler.get_fe().dofs_per_vertex) == false,
1715  ExcInternalError());
1716  }
1717 
1718 
1719 
1727  template <int dim, int spacedim>
1728  static void
1729  renumber_cell_dofs(
1730  const std::vector<types::global_dof_index> &new_numbers,
1731  const IndexSet & indices,
1732  DoFHandler<dim, spacedim> & dof_handler)
1733  {
1734  for (unsigned int level = 0; level < dof_handler.levels.size();
1735  ++level)
1736  for (std::vector<types::global_dof_index>::iterator i =
1737  dof_handler.levels[level]->dof_object.dofs.begin();
1738  i != dof_handler.levels[level]->dof_object.dofs.end();
1739  ++i)
1740  if (*i != numbers::invalid_dof_index)
1741  *i = ((indices.size() == 0) ?
1742  new_numbers[*i] :
1743  new_numbers[indices.index_within_set(*i)]);
1744  }
1745 
1746 
1747 
1755  template <int spacedim>
1756  static void
1757  renumber_face_dofs(
1758  const std::vector<types::global_dof_index> & /*new_numbers*/,
1759  const IndexSet & /*indices*/,
1760  DoFHandler<1, spacedim> & /*dof_handler*/)
1761  {
1762  // nothing to do in 1d since there are no separate faces
1763  }
1764 
1765 
1766 
1767  template <int spacedim>
1768  static void
1769  renumber_face_dofs(
1770  const std::vector<types::global_dof_index> &new_numbers,
1771  const IndexSet & indices,
1772  DoFHandler<2, spacedim> & dof_handler)
1773  {
1774  // treat dofs on lines
1775  for (std::vector<types::global_dof_index>::iterator i =
1776  dof_handler.faces->lines.dofs.begin();
1777  i != dof_handler.faces->lines.dofs.end();
1778  ++i)
1779  if (*i != numbers::invalid_dof_index)
1780  *i = ((indices.size() == 0) ?
1781  new_numbers[*i] :
1782  new_numbers[indices.index_within_set(*i)]);
1783  }
1784 
1785 
1786 
1787  template <int spacedim>
1788  static void
1789  renumber_face_dofs(
1790  const std::vector<types::global_dof_index> &new_numbers,
1791  const IndexSet & indices,
1792  DoFHandler<3, spacedim> & dof_handler)
1793  {
1794  // treat dofs on lines
1795  for (std::vector<types::global_dof_index>::iterator i =
1796  dof_handler.faces->lines.dofs.begin();
1797  i != dof_handler.faces->lines.dofs.end();
1798  ++i)
1799  if (*i != numbers::invalid_dof_index)
1800  *i = ((indices.size() == 0) ?
1801  new_numbers[*i] :
1802  new_numbers[indices.index_within_set(*i)]);
1803 
1804  // treat dofs on quads
1805  for (std::vector<types::global_dof_index>::iterator i =
1806  dof_handler.faces->quads.dofs.begin();
1807  i != dof_handler.faces->quads.dofs.end();
1808  ++i)
1809  if (*i != numbers::invalid_dof_index)
1810  *i = ((indices.size() == 0) ?
1811  new_numbers[*i] :
1812  new_numbers[indices.index_within_set(*i)]);
1813  }
1814 
1815 
1816 
1817  template <int dim, int spacedim>
1818  static void
1819  renumber_vertex_dofs(
1820  const std::vector<types::global_dof_index> &new_numbers,
1821  const IndexSet & indices,
1822  hp::DoFHandler<dim, spacedim> & dof_handler,
1823  const bool check_validity)
1824  {
1825  for (unsigned int vertex_index = 0;
1826  vertex_index < dof_handler.get_triangulation().n_vertices();
1827  ++vertex_index)
1828  {
1829  const unsigned int n_active_fe_indices =
1830  ::internal::DoFAccessorImplementation::Implementation::
1831  n_active_vertex_fe_indices(dof_handler, vertex_index);
1832 
1833  // if this vertex is unused, then we really ought not to have
1834  // allocated any space for it, i.e., n_active_fe_indices should be
1835  // zero, and there is no space to actually store dof indices for
1836  // this vertex
1837  if (dof_handler.get_triangulation().vertex_used(vertex_index) ==
1838  false)
1839  Assert(n_active_fe_indices == 0, ExcInternalError());
1840 
1841  // otherwise the vertex is used; it may still not hold any dof
1842  // indices if it is located on an artificial cell and not adjacent
1843  // to a ghost cell, but in that case there is simply nothing for
1844  // us to do
1845  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
1846  {
1847  const unsigned int fe_index =
1848  ::internal::DoFAccessorImplementation::
1849  Implementation::nth_active_vertex_fe_index(dof_handler,
1850  vertex_index,
1851  f);
1852 
1853  for (unsigned int d = 0;
1854  d < dof_handler.get_fe(fe_index).dofs_per_vertex;
1855  ++d)
1856  {
1857  const types::global_dof_index old_dof_index =
1858  ::internal::DoFAccessorImplementation::
1859  Implementation::get_vertex_dof_index(dof_handler,
1860  vertex_index,
1861  fe_index,
1862  d);
1863 
1864  // if check_validity was set, then we are to verify that
1865  // the previous indices were all valid. this really should
1866  // be the case: we allocated space for these vertex dofs,
1867  // i.e., at least one adjacent cell has a valid
1868  // active_fe_index, so there are DoFs that really live
1869  // on this vertex. if check_validity is set, then we
1870  // must make sure that they have been set to something
1871  // useful
1872  if (check_validity)
1873  Assert(old_dof_index != numbers::invalid_dof_index,
1874  ExcInternalError());
1875 
1876  if (old_dof_index != numbers::invalid_dof_index)
1877  ::internal::DoFAccessorImplementation::
1878  Implementation::set_vertex_dof_index(
1879  dof_handler,
1880  vertex_index,
1881  fe_index,
1882  d,
1883  (indices.size() == 0) ?
1884  (new_numbers[old_dof_index]) :
1885  (new_numbers[indices.index_within_set(
1886  old_dof_index)]));
1887  }
1888  }
1889  }
1890  }
1891 
1892 
1893 
1894  template <int dim, int spacedim>
1895  static void
1896  renumber_cell_dofs(
1897  const std::vector<types::global_dof_index> &new_numbers,
1898  const IndexSet & indices,
1899  hp::DoFHandler<dim, spacedim> & dof_handler)
1900  {
1902  cell = dof_handler.begin_active();
1903  cell != dof_handler.end();
1904  ++cell)
1905  if (!cell->is_artificial())
1906  {
1907  const unsigned int fe_index = cell->active_fe_index();
1908 
1909  for (unsigned int d = 0;
1910  d < dof_handler.get_fe(fe_index)
1911  .template n_dofs_per_object<dim>();
1912  ++d)
1913  {
1914  const types::global_dof_index old_dof_index =
1915  cell->dof_index(d, fe_index);
1916  if (old_dof_index != numbers::invalid_dof_index)
1917  cell->set_dof_index(
1918  d,
1919  (indices.size() == 0) ?
1920  (new_numbers[old_dof_index]) :
1921  (new_numbers[indices.index_within_set(
1922  old_dof_index)]),
1923  fe_index);
1924  }
1925  }
1926  }
1927 
1928 
1929 
1930  template <int spacedim>
1931  static void
1932  renumber_face_dofs(
1933  const std::vector<types::global_dof_index> & /*new_numbers*/,
1934  const IndexSet & /*indices*/,
1935  hp::DoFHandler<1, spacedim> & /*dof_handler*/)
1936  {
1937  // nothing to do in 1d since there are no separate faces -- we've
1938  // already taken care of this when dealing with the vertices
1939  }
1940 
1941 
1942 
1943  template <int spacedim>
1944  static void
1945  renumber_face_dofs(
1946  const std::vector<types::global_dof_index> &new_numbers,
1947  const IndexSet & indices,
1948  hp::DoFHandler<2, spacedim> & dof_handler)
1949  {
1950  const unsigned int dim = 2;
1951 
1952  // deal with DoFs on lines
1953  {
1954  // save user flags on lines so we can use them to mark lines
1955  // we've already treated
1956  std::vector<bool> saved_line_user_flags;
1957  const_cast<::Triangulation<dim, spacedim> &>(
1958  dof_handler.get_triangulation())
1959  .save_user_flags_line(saved_line_user_flags);
1960  const_cast<::Triangulation<dim, spacedim> &>(
1961  dof_handler.get_triangulation())
1962  .clear_user_flags_line();
1963 
1965  cell = dof_handler.begin_active();
1966  cell != dof_handler.end();
1967  ++cell)
1968  if (!cell->is_artificial())
1969  for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell;
1970  ++l)
1971  if (cell->line(l)->user_flag_set() == false)
1972  {
1973  const typename hp::DoFHandler<dim,
1974  spacedim>::line_iterator
1975  line = cell->line(l);
1976  line->set_user_flag();
1977 
1978  const unsigned int n_active_fe_indices =
1979  line->n_active_fe_indices();
1980 
1981  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
1982  {
1983  const unsigned int fe_index =
1984  line->nth_active_fe_index(f);
1985 
1986  for (unsigned int d = 0;
1987  d < dof_handler.get_fe(fe_index).dofs_per_line;
1988  ++d)
1989  {
1990  const types::global_dof_index old_dof_index =
1991  line->dof_index(d, fe_index);
1992  if (old_dof_index != numbers::invalid_dof_index)
1993  line->set_dof_index(
1994  d,
1995  (indices.size() == 0) ?
1996  (new_numbers[old_dof_index]) :
1997  (new_numbers[indices.index_within_set(
1998  old_dof_index)]),
1999  fe_index);
2000  }
2001  }
2002  }
2003 
2004  // at the end, restore the user
2005  // flags for the lines
2006  const_cast<::Triangulation<dim, spacedim> &>(
2007  dof_handler.get_triangulation())
2008  .load_user_flags_line(saved_line_user_flags);
2009  }
2010  }
2011 
2012 
2013 
2014  template <int spacedim>
2015  static void
2016  renumber_face_dofs(
2017  const std::vector<types::global_dof_index> &new_numbers,
2018  const IndexSet & indices,
2019  hp::DoFHandler<3, spacedim> & dof_handler)
2020  {
2021  const unsigned int dim = 3;
2022 
2023  // deal with DoFs on lines
2024  {
2025  // save user flags on lines so we can use them to mark lines
2026  // we've already treated
2027  std::vector<bool> saved_line_user_flags;
2028  const_cast<::Triangulation<dim, spacedim> &>(
2029  dof_handler.get_triangulation())
2030  .save_user_flags_line(saved_line_user_flags);
2031  const_cast<::Triangulation<dim, spacedim> &>(
2032  dof_handler.get_triangulation())
2033  .clear_user_flags_line();
2034 
2036  cell = dof_handler.begin_active();
2037  cell != dof_handler.end();
2038  ++cell)
2039  if (!cell->is_artificial())
2040  for (unsigned int l = 0; l < GeometryInfo<dim>::lines_per_cell;
2041  ++l)
2042  if (cell->line(l)->user_flag_set() == false)
2043  {
2044  const typename hp::DoFHandler<dim,
2045  spacedim>::line_iterator
2046  line = cell->line(l);
2047  line->set_user_flag();
2048 
2049  const unsigned int n_active_fe_indices =
2050  line->n_active_fe_indices();
2051 
2052  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
2053  {
2054  const unsigned int fe_index =
2055  line->nth_active_fe_index(f);
2056 
2057  for (unsigned int d = 0;
2058  d < dof_handler.get_fe(fe_index).dofs_per_line;
2059  ++d)
2060  {
2061  const types::global_dof_index old_dof_index =
2062  line->dof_index(d, fe_index);
2063  if (old_dof_index != numbers::invalid_dof_index)
2064  line->set_dof_index(
2065  d,
2066  (indices.size() == 0) ?
2067  (new_numbers[old_dof_index]) :
2068  (new_numbers[indices.index_within_set(
2069  old_dof_index)]),
2070  fe_index);
2071  }
2072  }
2073  }
2074 
2075  // at the end, restore the user
2076  // flags for the lines
2077  const_cast<::Triangulation<dim, spacedim> &>(
2078  dof_handler.get_triangulation())
2079  .load_user_flags_line(saved_line_user_flags);
2080  }
2081 
2082  // then deal with dofs on quads
2083  {
2084  std::vector<bool> saved_quad_user_flags;
2085  const_cast<::Triangulation<dim, spacedim> &>(
2086  dof_handler.get_triangulation())
2087  .save_user_flags_quad(saved_quad_user_flags);
2088  const_cast<::Triangulation<dim, spacedim> &>(
2089  dof_handler.get_triangulation())
2090  .clear_user_flags_quad();
2091 
2093  cell = dof_handler.begin_active();
2094  cell != dof_handler.end();
2095  ++cell)
2096  if (!cell->is_artificial())
2097  for (unsigned int q = 0; q < GeometryInfo<dim>::quads_per_cell;
2098  ++q)
2099  if (cell->quad(q)->user_flag_set() == false)
2100  {
2101  const typename hp::DoFHandler<dim,
2102  spacedim>::quad_iterator
2103  quad = cell->quad(q);
2104  quad->set_user_flag();
2105 
2106  const unsigned int n_active_fe_indices =
2107  quad->n_active_fe_indices();
2108 
2109  for (unsigned int f = 0; f < n_active_fe_indices; ++f)
2110  {
2111  const unsigned int fe_index =
2112  quad->nth_active_fe_index(f);
2113 
2114  for (unsigned int d = 0;
2115  d < dof_handler.get_fe(fe_index).dofs_per_quad;
2116  ++d)
2117  {
2118  const types::global_dof_index old_dof_index =
2119  quad->dof_index(d, fe_index);
2120  if (old_dof_index != numbers::invalid_dof_index)
2121  quad->set_dof_index(
2122  d,
2123  (indices.size() == 0) ?
2124  (new_numbers[old_dof_index]) :
2125  (new_numbers[indices.index_within_set(
2126  old_dof_index)]),
2127  fe_index);
2128  }
2129  }
2130  }
2131 
2132  // at the end, restore the user flags for the quads
2133  const_cast<::Triangulation<dim, spacedim> &>(
2134  dof_handler.get_triangulation())
2135  .load_user_flags_quad(saved_quad_user_flags);
2136  }
2137  }
2138 
2139 
2140 
2152  template <class DoFHandlerType>
2153  static void
2154  renumber_dofs(const std::vector<types::global_dof_index> &new_numbers,
2155  const IndexSet & indices,
2156  DoFHandlerType & dof_handler,
2157  const bool check_validity)
2158  {
2159  if (DoFHandlerType::dimension == 1)
2160  Assert(indices == IndexSet(0), ExcNotImplemented());
2161 
2162  // renumber DoF indices on vertices, cells, and faces. this
2163  // can be done in parallel because the respective functions
2164  // work on separate data structures
2165  Threads::TaskGroup<> tasks;
2166  tasks += Threads::new_task([&]() {
2167  renumber_vertex_dofs(new_numbers,
2168  indices,
2169  dof_handler,
2170  check_validity);
2171  });
2172  tasks += Threads::new_task(
2173  [&]() { renumber_face_dofs(new_numbers, indices, dof_handler); });
2174  tasks += Threads::new_task(
2175  [&]() { renumber_cell_dofs(new_numbers, indices, dof_handler); });
2176  tasks.join_all();
2177 
2178  // update the cache used for cell dof indices
2179  update_all_active_cell_dof_indices_caches(dof_handler);
2180  }
2181 
2182 
2183 
2184  /* --------------------- renumber_mg_dofs functionality ----------------
2185  */
2186 
2194  template <int dim, int spacedim>
2195  static void
2196  renumber_vertex_mg_dofs(
2197  const std::vector<::types::global_dof_index> &new_numbers,
2198  const IndexSet & indices,
2199  DoFHandler<dim, spacedim> & dof_handler,
2200  const unsigned int level,
2201  const bool check_validity)
2202  {
2203  Assert(level < dof_handler.get_triangulation().n_levels(),
2204  ExcInternalError());
2205 
2206  for (typename std::vector<
2207  typename DoFHandler<dim, spacedim>::MGVertexDoFs>::iterator i =
2208  dof_handler.mg_vertex_dofs.begin();
2209  i != dof_handler.mg_vertex_dofs.end();
2210  ++i)
2211  // if the present vertex lives on the current level
2212  if ((i->get_coarsest_level() <= level) &&
2213  (i->get_finest_level() >= level))
2214  for (unsigned int d = 0; d < dof_handler.get_fe().dofs_per_vertex;
2215  ++d)
2216  {
2217  const ::types::global_dof_index idx =
2218  i->get_index(level,
2219  d,
2220  dof_handler.get_fe().dofs_per_vertex);
2221 
2222  if (check_validity)
2224  ExcInternalError());
2225 
2226  if (idx != numbers::invalid_dof_index)
2227  i->set_index(
2228  level,
2229  d,
2230  dof_handler.get_fe().dofs_per_vertex,
2231  (indices.size() == 0) ?
2232  (new_numbers[idx]) :
2233  (new_numbers[indices.index_within_set(idx)]));
2234  }
2235  }
2236 
2237 
2238 
2246  template <int dim, int spacedim>
2247  static void
2248  renumber_cell_mg_dofs(
2249  const std::vector<::types::global_dof_index> &new_numbers,
2250  const IndexSet & indices,
2251  DoFHandler<dim, spacedim> & dof_handler,
2252  const unsigned int level)
2253  {
2254  for (std::vector<types::global_dof_index>::iterator i =
2255  dof_handler.mg_levels[level]->dof_object.dofs.begin();
2256  i != dof_handler.mg_levels[level]->dof_object.dofs.end();
2257  ++i)
2258  {
2259  if (*i != numbers::invalid_dof_index)
2260  {
2261  Assert((indices.size() > 0 ? indices.is_element(*i) :
2262  (*i < new_numbers.size())),
2263  ExcInternalError());
2264  *i = (indices.size() == 0) ?
2265  (new_numbers[*i]) :
2266  (new_numbers[indices.index_within_set(*i)]);
2267  }
2268  }
2269  }
2270 
2271 
2272 
2280  template <int spacedim>
2281  static void
2282  renumber_face_mg_dofs(
2283  const std::vector<types::global_dof_index> & /*new_numbers*/,
2284  const IndexSet & /*indices*/,
2285  DoFHandler<1, spacedim> & /*dof_handler*/,
2286  const unsigned int /*level*/,
2287  const bool /*check_validity*/)
2288  {
2289  // nothing to do in 1d because there are no separate faces
2290  }
2291 
2292 
2293 
2294  template <int spacedim>
2295  static void
2296  renumber_face_mg_dofs(
2297  const std::vector<::types::global_dof_index> &new_numbers,
2298  const IndexSet & indices,
2299  DoFHandler<2, spacedim> & dof_handler,
2300  const unsigned int level,
2301  const bool check_validity)
2302  {
2303  if (dof_handler.get_fe().dofs_per_line > 0)
2304  {
2305  // save user flags as they will be modified
2306  std::vector<bool> user_flags;
2307  dof_handler.get_triangulation().save_user_flags(user_flags);
2308  const_cast<::Triangulation<2, spacedim> &>(
2309  dof_handler.get_triangulation())
2310  .clear_user_flags();
2311 
2312  // flag all lines adjacent to cells of the current
2313  // level, as those lines logically belong to the same
2314  // level as the cell, at least for for isotropic
2315  // refinement
2316  typename DoFHandler<2, spacedim>::level_cell_iterator cell,
2317  endc = dof_handler.end(level);
2318  for (cell = dof_handler.begin(level); cell != endc; ++cell)
2319  for (unsigned int line = 0;
2320  line < GeometryInfo<2>::faces_per_cell;
2321  ++line)
2322  cell->face(line)->set_user_flag();
2323 
2324  for (typename DoFHandler<2, spacedim>::cell_iterator cell =
2325  dof_handler.begin();
2326  cell != dof_handler.end();
2327  ++cell)
2328  for (unsigned int l = 0; l < GeometryInfo<2>::lines_per_cell;
2329  ++l)
2330  if (cell->line(l)->user_flag_set())
2331  {
2332  for (unsigned int d = 0;
2333  d < dof_handler.get_fe().dofs_per_line;
2334  ++d)
2335  {
2336  const ::types::global_dof_index idx =
2337  cell->line(l)->mg_dof_index(level, d);
2338  if (check_validity)
2340  ExcInternalError());
2341 
2342  if (idx != numbers::invalid_dof_index)
2343  cell->line(l)->set_mg_dof_index(
2344  level,
2345  d,
2346  ((indices.size() == 0) ?
2347  new_numbers[idx] :
2348  new_numbers[indices.index_within_set(idx)]));
2349  }
2350  cell->line(l)->clear_user_flag();
2351  }
2352  // finally, restore user flags
2353  const_cast<::Triangulation<2, spacedim> &>(
2354  dof_handler.get_triangulation())
2355  .load_user_flags(user_flags);
2356  }
2357  }
2358 
2359 
2360 
2361  template <int spacedim>
2362  static void
2363  renumber_face_mg_dofs(
2364  const std::vector<::types::global_dof_index> &new_numbers,
2365  const IndexSet & indices,
2366  DoFHandler<3, spacedim> & dof_handler,
2367  const unsigned int level,
2368  const bool check_validity)
2369  {
2370  if (dof_handler.get_fe().dofs_per_line > 0 ||
2371  dof_handler.get_fe().dofs_per_quad > 0)
2372  {
2373  // save user flags as they will be modified
2374  std::vector<bool> user_flags;
2375  dof_handler.get_triangulation().save_user_flags(user_flags);
2376  const_cast<::Triangulation<3, spacedim> &>(
2377  dof_handler.get_triangulation())
2378  .clear_user_flags();
2379 
2380  // flag all lines adjacent to cells of the current
2381  // level, as those lines logically belong to the same
2382  // level as the cell, at least for isotropic refinement
2383  typename DoFHandler<3, spacedim>::level_cell_iterator cell,
2384  endc = dof_handler.end(level);
2385  for (cell = dof_handler.begin(level); cell != endc; ++cell)
2386  for (unsigned int line = 0;
2387  line < GeometryInfo<3>::lines_per_cell;
2388  ++line)
2389  cell->line(line)->set_user_flag();
2390 
2391  for (typename DoFHandler<3, spacedim>::cell_iterator cell =
2392  dof_handler.begin();
2393  cell != dof_handler.end();
2394  ++cell)
2395  for (unsigned int l = 0; l < GeometryInfo<3>::lines_per_cell;
2396  ++l)
2397  if (cell->line(l)->user_flag_set())
2398  {
2399  for (unsigned int d = 0;
2400  d < dof_handler.get_fe().dofs_per_line;
2401  ++d)
2402  {
2403  const ::types::global_dof_index idx =
2404  cell->line(l)->mg_dof_index(level, d);
2405  if (check_validity)
2407  ExcInternalError());
2408 
2409  if (idx != numbers::invalid_dof_index)
2410  cell->line(l)->set_mg_dof_index(
2411  level,
2412  d,
2413  ((indices.size() == 0) ?
2414  new_numbers[idx] :
2415  new_numbers[indices.index_within_set(idx)]));
2416  }
2417  cell->line(l)->clear_user_flag();
2418  }
2419 
2420  // flag all quads adjacent to cells of the current level, as
2421  // those quads logically belong to the same level as the cell,
2422  // at least for isotropic refinement
2423  for (cell = dof_handler.begin(level); cell != endc; ++cell)
2424  for (unsigned int quad = 0;
2425  quad < GeometryInfo<3>::quads_per_cell;
2426  ++quad)
2427  cell->quad(quad)->set_user_flag();
2428 
2429  for (typename DoFHandler<3, spacedim>::cell_iterator cell =
2430  dof_handler.begin();
2431  cell != dof_handler.end();
2432  ++cell)
2433  for (unsigned int l = 0; l < GeometryInfo<3>::quads_per_cell;
2434  ++l)
2435  if (cell->quad(l)->user_flag_set())
2436  {
2437  for (unsigned int d = 0;
2438  d < dof_handler.get_fe().dofs_per_quad;
2439  ++d)
2440  {
2441  const ::types::global_dof_index idx =
2442  cell->quad(l)->mg_dof_index(level, d);
2443  if (check_validity)
2445  ExcInternalError());
2446 
2447  if (idx != numbers::invalid_dof_index)
2448  cell->quad(l)->set_mg_dof_index(
2449  level,
2450  d,
2451  ((indices.size() == 0) ?
2452  new_numbers[idx] :
2453  new_numbers[indices.index_within_set(idx)]));
2454  }
2455  cell->quad(l)->clear_user_flag();
2456  }
2457 
2458  // finally, restore user flags
2459  const_cast<::Triangulation<3, spacedim> &>(
2460  dof_handler.get_triangulation())
2461  .load_user_flags(user_flags);
2462  }
2463  }
2464 
2465 
2466 
2467  template <int dim, int spacedim>
2468  static void
2469  renumber_mg_dofs(
2470  const std::vector<::types::global_dof_index> &new_numbers,
2471  const IndexSet & indices,
2472  DoFHandler<dim, spacedim> & dof_handler,
2473  const unsigned int level,
2474  const bool check_validity)
2475  {
2476  Assert(level < dof_handler.get_triangulation().n_global_levels(),
2477  ExcInternalError());
2478 
2479  // renumber DoF indices on vertices, cells, and faces. this
2480  // can be done in parallel because the respective functions
2481  // work on separate data structures
2482  Threads::TaskGroup<> tasks;
2483  tasks += Threads::new_task([&]() {
2484  renumber_vertex_mg_dofs(
2485  new_numbers, indices, dof_handler, level, check_validity);
2486  });
2487  tasks += Threads::new_task([&]() {
2488  renumber_face_mg_dofs(
2489  new_numbers, indices, dof_handler, level, check_validity);
2490  });
2491  tasks += Threads::new_task([&]() {
2492  renumber_cell_mg_dofs(new_numbers, indices, dof_handler, level);
2493  });
2494  tasks.join_all();
2495  }
2496 
2497 
2498 
2499  template <int dim, int spacedim>
2500  static void
2501  renumber_mg_dofs(
2502  const std::vector<::types::global_dof_index> & /*new_numbers*/,
2503  const IndexSet & /*indices*/,
2504  hp::DoFHandler<dim, spacedim> & /*dof_handler*/,
2505  const unsigned int /*level*/,
2506  const bool /*check_validity*/)
2507  {
2508  Assert(false, ExcNotImplemented());
2509  }
2510  };
2511 
2512 
2513 
2514  /* --------------------- class Sequential ---------------- */
2515 
2516 
2517 
2518  template <class DoFHandlerType>
2519  Sequential<DoFHandlerType>::Sequential(DoFHandlerType &dof_handler)
2520  : dof_handler(&dof_handler)
2521  {}
2522 
2523 
2524 
2525  template <class DoFHandlerType>
2526  NumberCache
2528  {
2529  const types::global_dof_index n_dofs =
2530  Implementation::distribute_dofs(numbers::invalid_subdomain_id,
2531  *dof_handler);
2532 
2533  // return a sequential, complete index set
2534  return NumberCache(n_dofs);
2535  }
2536 
2537 
2538 
2539  template <class DoFHandlerType>
2540  std::vector<NumberCache>
2542  {
2543  std::vector<bool> user_flags;
2544  dof_handler->get_triangulation().save_user_flags(user_flags);
2545 
2546  const_cast<::Triangulation<DoFHandlerType::dimension,
2547  DoFHandlerType::space_dimension> &>(
2548  dof_handler->get_triangulation())
2549  .clear_user_flags();
2550 
2551  std::vector<NumberCache> number_caches;
2552  number_caches.reserve(dof_handler->get_triangulation().n_levels());
2553  for (unsigned int level = 0;
2554  level < dof_handler->get_triangulation().n_levels();
2555  ++level)
2556  {
2557  // first distribute dofs on this level
2558  const types::global_dof_index n_level_dofs =
2559  Implementation::distribute_dofs_on_level(
2560  numbers::invalid_subdomain_id, *dof_handler, level);
2561 
2562  // then add a complete, sequential index set
2563  number_caches.emplace_back(NumberCache(n_level_dofs));
2564  }
2565 
2566  const_cast<::Triangulation<DoFHandlerType::dimension,
2567  DoFHandlerType::space_dimension> &>(
2568  dof_handler->get_triangulation())
2569  .load_user_flags(user_flags);
2570 
2571  return number_caches;
2572  }
2573 
2574 
2575 
2576  template <class DoFHandlerType>
2577  NumberCache
2579  const std::vector<types::global_dof_index> &new_numbers) const
2580  {
2581  Implementation::renumber_dofs(new_numbers,
2582  IndexSet(0),
2583  *dof_handler,
2584  true);
2585 
2586  // return a sequential, complete index set. take into account that the
2587  // number of DoF indices may in fact be smaller than there were before
2588  // if some previously separately numbered dofs have been identified.
2589  // this is, for example, what the hp::DoFHandler does: it first
2590  // enumerates all DoFs on cells independently, and then unifies
2591  // some located at vertices or faces; this leaves us with fewer
2592  // DoFs than there were before, so use the largest index as
2593  // the one to determine the size of the index space
2594  return NumberCache(
2595  *std::max_element(new_numbers.begin(), new_numbers.end()) + 1);
2596  }
2597 
2598 
2599 
2600  template <class DoFHandlerType>
2601  NumberCache
2603  const unsigned int level,
2604  const std::vector<types::global_dof_index> &new_numbers) const
2605  {
2606  Implementation::renumber_mg_dofs(
2607  new_numbers, IndexSet(0), *dof_handler, level, true);
2608 
2609  // return a sequential, complete index set
2610  return NumberCache(new_numbers.size());
2611  }
2612 
2613 
2614  /* --------------------- class ParallelShared ---------------- */
2615 
2616 
2617  template <class DoFHandlerType>
2619  DoFHandlerType &dof_handler)
2620  : dof_handler(&dof_handler)
2621  {}
2622 
2623 
2624 
2625  namespace
2626  {
2635  template <class DoFHandlerType>
2636  std::vector<types::subdomain_id>
2637  get_dof_subdomain_association(const DoFHandlerType & dof_handler,
2638  const types::global_dof_index n_dofs,
2639  const unsigned int n_procs)
2640  {
2641  (void)n_procs;
2642  std::vector<types::subdomain_id> subdomain_association(
2644  std::vector<types::global_dof_index> local_dof_indices;
2645  local_dof_indices.reserve(DoFTools::max_dofs_per_cell(dof_handler));
2646 
2647  // loop over all cells and record which subdomain a DoF belongs to.
2648  // give to the smaller subdomain_id in case it is on an interface
2649  typename DoFHandlerType::active_cell_iterator
2650  cell = dof_handler.begin_active(),
2651  endc = dof_handler.end();
2652  for (; cell != endc; ++cell)
2653  {
2654  // get the owner of the cell; note that we have made sure above
2655  // that all cells are either locally owned or ghosts (not
2656  // artificial), so this call will always yield the true owner
2657  const types::subdomain_id subdomain_id = cell->subdomain_id();
2658  const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
2659  local_dof_indices.resize(dofs_per_cell);
2660  cell->get_dof_indices(local_dof_indices);
2661 
2662  // set subdomain ids. if dofs already have their values set then
2663  // they must be on partition interfaces. In that case assign them
2664  // to the processor with the smaller subdomain id.
2665  for (unsigned int i = 0; i < dofs_per_cell; ++i)
2666  if (subdomain_association[local_dof_indices[i]] ==
2668  subdomain_association[local_dof_indices[i]] = subdomain_id;
2669  else if (subdomain_association[local_dof_indices[i]] >
2670  subdomain_id)
2671  {
2672  subdomain_association[local_dof_indices[i]] = subdomain_id;
2673  }
2674  }
2675 
2676  Assert(std::find(subdomain_association.begin(),
2677  subdomain_association.end(),
2679  subdomain_association.end(),
2680  ExcInternalError());
2681 
2682  Assert(*std::max_element(subdomain_association.begin(),
2683  subdomain_association.end()) < n_procs,
2684  ExcInternalError());
2685 
2686  return subdomain_association;
2687  }
2688 
2689 
2696  template <class DoFHandlerType>
2697  std::vector<types::subdomain_id>
2698  get_dof_level_subdomain_association(
2699  const DoFHandlerType & dof_handler,
2700  const types::global_dof_index n_dofs_on_level,
2701  const unsigned int n_procs,
2702  const unsigned int level)
2703  {
2704  (void)n_procs;
2705  std::vector<types::subdomain_id> level_subdomain_association(
2706  n_dofs_on_level, numbers::invalid_subdomain_id);
2707  std::vector<types::global_dof_index> local_dof_indices;
2708  local_dof_indices.reserve(DoFTools::max_dofs_per_cell(dof_handler));
2709 
2710  // loop over all cells and record which subdomain a DoF belongs to.
2711  // interface goes to proccessor with smaller subdomain id
2712  typename DoFHandlerType::cell_iterator cell =
2713  dof_handler.begin(level),
2714  endc = dof_handler.end(level);
2715  for (; cell != endc; ++cell)
2716  {
2717  // get the owner of the cell; note that we have made sure above
2718  // that all cells are either locally owned or ghosts (not
2719  // artificial), so this call will always yield the true owner
2720  const types::subdomain_id level_subdomain_id =
2721  cell->level_subdomain_id();
2722  const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
2723  local_dof_indices.resize(dofs_per_cell);
2724  cell->get_mg_dof_indices(local_dof_indices);
2725 
2726  // set level subdomain ids. if dofs already have their values set
2727  // then they must be on partition interfaces. In that case assign
2728  // them to the processor with the smaller subdomain id.
2729  for (unsigned int i = 0; i < dofs_per_cell; ++i)
2730  if (level_subdomain_association[local_dof_indices[i]] ==
2732  level_subdomain_association[local_dof_indices[i]] =
2733  level_subdomain_id;
2734  else if (level_subdomain_association[local_dof_indices[i]] >
2735  level_subdomain_id)
2736  {
2737  level_subdomain_association[local_dof_indices[i]] =
2738  level_subdomain_id;
2739  }
2740  }
2741 
2742  Assert(std::find(level_subdomain_association.begin(),
2743  level_subdomain_association.end(),
2745  level_subdomain_association.end(),
2746  ExcInternalError());
2747 
2748  Assert(*std::max_element(level_subdomain_association.begin(),
2749  level_subdomain_association.end()) < n_procs,
2750  ExcInternalError());
2751 
2752  return level_subdomain_association;
2753  }
2754  } // namespace
2755 
2756 
2757 
2758  template <class DoFHandlerType>
2759  NumberCache
2761  {
2762  const unsigned int dim = DoFHandlerType::dimension;
2763  const unsigned int spacedim = DoFHandlerType::space_dimension;
2764 
2766  (dynamic_cast<const parallel::shared::Triangulation<dim, spacedim> *>(
2767  &this->dof_handler->get_triangulation()));
2768  Assert(tr != nullptr, ExcInternalError());
2769 
2770  const unsigned int n_procs =
2772 
2773  // If the underlying shared::Tria allows artificial cells,
2774  // then save the current set of subdomain ids, and set
2775  // subdomain ids to the "true" owner of each cell. we later
2776  // restore these flags
2777  std::vector<types::subdomain_id> saved_subdomain_ids;
2778  if (tr->with_artificial_cells())
2779  {
2780  saved_subdomain_ids.resize(tr->n_active_cells());
2781 
2783  active_cell_iterator
2784  cell = this->dof_handler->get_triangulation().begin_active(),
2785  endc = this->dof_handler->get_triangulation().end();
2786 
2787  const std::vector<types::subdomain_id> &true_subdomain_ids =
2789 
2790  for (unsigned int index = 0; cell != endc; ++cell, ++index)
2791  {
2792  saved_subdomain_ids[index] = cell->subdomain_id();
2793  cell->set_subdomain_id(true_subdomain_ids[index]);
2794  }
2795  }
2796 
2797  // first let the sequential algorithm do its magic. it is going to
2798  // enumerate DoFs on all cells, regardless of owner
2799  const types::global_dof_index n_dofs =
2800  Implementation::distribute_dofs(numbers::invalid_subdomain_id,
2801  *this->dof_handler);
2802 
2803  // then re-enumerate them based on their subdomain association.
2804  // for this, we first have to identify for each current DoF
2805  // index which subdomain they belong to. ideally, we would
2806  // like to call DoFRenumbering::subdomain_wise(), but
2807  // because the NumberCache of the current DoFHandler is not
2808  // fully set up yet, we can't quite do that. also, that
2809  // function has to deal with other kinds of triangulations as
2810  // well, whereas we here know what kind of triangulation
2811  // we have and can simplify the code accordingly
2812  std::vector<types::global_dof_index> new_dof_indices(
2813  n_dofs, numbers::invalid_dof_index);
2814  {
2815  // first get the association of each dof with a subdomain and
2816  // determine the total number of subdomain ids used
2817  const std::vector<types::subdomain_id> subdomain_association =
2818  get_dof_subdomain_association(*this->dof_handler, n_dofs, n_procs);
2819 
2820  // then renumber the subdomains by first looking at those belonging
2821  // to subdomain 0, then those of subdomain 1, etc. note that the
2822  // algorithm is stable, i.e. if two dofs i,j have i<j and belong to
2823  // the same subdomain, then they will be in this order also after
2824  // reordering
2825  types::global_dof_index next_free_index = 0;
2826  for (types::subdomain_id subdomain = 0; subdomain < n_procs;
2827  ++subdomain)
2828  for (types::global_dof_index i = 0; i < n_dofs; ++i)
2829  if (subdomain_association[i] == subdomain)
2830  {
2831  Assert(new_dof_indices[i] == numbers::invalid_dof_index,
2832  ExcInternalError());
2833  new_dof_indices[i] = next_free_index;
2834  ++next_free_index;
2835  }
2836 
2837  // we should have numbered all dofs
2838  Assert(next_free_index == n_dofs, ExcInternalError());
2839  Assert(std::find(new_dof_indices.begin(),
2840  new_dof_indices.end(),
2841  numbers::invalid_dof_index) == new_dof_indices.end(),
2842  ExcInternalError());
2843  }
2844  // finally do the renumbering. we can use the sequential
2845  // version of the function because we do things on all
2846  // cells and all cells have their subdomain ids and DoFs
2847  // correctly set
2848  Implementation::renumber_dofs(new_dof_indices,
2849  IndexSet(0),
2850  *this->dof_handler,
2851  true);
2852 
2853  // update the number cache. for this, we first have to find the
2854  // subdomain association for each DoF again following renumbering, from
2855  // which we can then compute the IndexSets of locally owned DoFs for all
2856  // processors. all other fields then follow from this
2857  //
2858  // given the way we enumerate degrees of freedom, the locally owned
2859  // ranges must all be contiguous and consecutive. this makes filling
2860  // the IndexSets cheap. an assertion at the top verifies that this
2861  // assumption is true
2862  const std::vector<types::subdomain_id> subdomain_association =
2863  get_dof_subdomain_association(*this->dof_handler, n_dofs, n_procs);
2864 
2865  for (unsigned int i = 1; i < n_dofs; ++i)
2866  Assert(subdomain_association[i] >= subdomain_association[i - 1],
2867  ExcInternalError());
2868 
2869  std::vector<IndexSet> locally_owned_dofs_per_processor(
2870  n_procs, IndexSet(n_dofs));
2871  {
2872  // we know that the set of subdomain indices is contiguous from
2873  // the assertion above; find the start and end index for each
2874  // processor, taking into account that sometimes a processor
2875  // may not in fact have any DoFs at all. we do the latter
2876  // by just identifying contiguous ranges of subdomain_ids
2877  // and filling IndexSets for those subdomains; subdomains
2878  // that don't appear will lead to IndexSets that are simply
2879  // never touched and remain empty as initialized above.
2880  unsigned int start_index = 0;
2881  unsigned int end_index = 0;
2882  while (start_index < n_dofs)
2883  {
2884  while ((end_index) < n_dofs &&
2885  (subdomain_association[end_index] ==
2886  subdomain_association[start_index]))
2887  ++end_index;
2888 
2889  // we've now identified a range of same indices. set that
2890  // range in the corresponding IndexSet
2891  if (end_index > start_index)
2892  {
2893  const unsigned int subdomain_owner =
2894  subdomain_association[start_index];
2895  locally_owned_dofs_per_processor[subdomain_owner].add_range(
2896  start_index, end_index);
2897  }
2898 
2899  // then move on to thinking about the next range
2900  start_index = end_index;
2901  }
2902  }
2903 
2904  // finally, restore current subdomain ids
2905  if (tr->with_artificial_cells())
2906  {
2908  active_cell_iterator
2909  cell = this->dof_handler->get_triangulation().begin_active(),
2910  endc = this->dof_handler->get_triangulation().end();
2911 
2912  for (unsigned int index = 0; cell != endc; ++cell, ++index)
2913  cell->set_subdomain_id(saved_subdomain_ids[index]);
2914  }
2915 
2916  // return a NumberCache object made up from the sets of locally
2917  // owned DoFs
2918  return NumberCache(
2919  locally_owned_dofs_per_processor,
2920  this->dof_handler->get_triangulation().locally_owned_subdomain());
2921  }
2922 
2923 
2924 
2925  template <class DoFHandlerType>
2926  std::vector<NumberCache>
2928  {
2929  const unsigned int dim = DoFHandlerType::dimension;
2930  const unsigned int spacedim = DoFHandlerType::space_dimension;
2931 
2933  (dynamic_cast<const parallel::shared::Triangulation<dim, spacedim> *>(
2934  &this->dof_handler->get_triangulation()));
2935  Assert(tr != nullptr, ExcInternalError());
2936 
2937  const unsigned int n_procs =
2939  const unsigned int n_levels = tr->n_global_levels();
2940 
2941  std::vector<NumberCache> number_caches;
2942  number_caches.reserve(n_levels);
2943 
2944  // We create an index set for each level
2945  for (unsigned int lvl = 0; lvl < n_levels; ++lvl)
2946  {
2947  // If the underlying shared::Tria allows artificial cells,
2948  // then save the current set of level subdomain ids, and set
2949  // subdomain ids to the "true" owner of each cell. we later
2950  // restore these flags
2951  // Note: "allows_artificial_cells" is currently enforced for
2952  // MG computations.
2953  std::vector<types::subdomain_id> saved_level_subdomain_ids;
2954  saved_level_subdomain_ids.resize(tr->n_cells(lvl));
2955  {
2956  typename parallel::shared::Triangulation<dim,
2957  spacedim>::cell_iterator
2958  cell = this->dof_handler->get_triangulation().begin(lvl),
2959  endc = this->dof_handler->get_triangulation().end(lvl);
2960 
2961  const std::vector<types::subdomain_id> &true_level_subdomain_ids =
2963 
2964  for (unsigned int index = 0; cell != endc; ++cell, ++index)
2965  {
2966  saved_level_subdomain_ids[index] = cell->level_subdomain_id();
2967  cell->set_level_subdomain_id(true_level_subdomain_ids[index]);
2968  }
2969  }
2970 
2971  // Next let the sequential algorithm do its magic. it is going to
2972  // enumerate DoFs on all cells on the given level, regardless of
2973  // owner
2974  const types::global_dof_index n_dofs_on_level =
2975  Implementation::distribute_dofs_on_level(
2976  numbers::invalid_subdomain_id, *this->dof_handler, lvl);
2977 
2978  // then re-enumerate them based on their level subdomain
2979  // association. for this, we first have to identify for each current
2980  // DoF index which subdomain they belong to. ideally, we would like
2981  // to call DoFRenumbering::subdomain_wise(), but because the
2982  // NumberCache of the current DoFHandler is not fully set up yet, we
2983  // can't quite do that. also, that function has to deal with other
2984  // kinds of triangulations as well, whereas we here know what kind
2985  // of triangulation we have and can simplify the code accordingly
2986  std::vector<types::global_dof_index> new_dof_indices(
2987  n_dofs_on_level, numbers::invalid_dof_index);
2988  {
2989  // first get the association of each dof with a subdomain and
2990  // determine the total number of subdomain ids used
2991  const std::vector<types::subdomain_id>
2992  level_subdomain_association =
2993  get_dof_level_subdomain_association(*this->dof_handler,
2994  n_dofs_on_level,
2995  n_procs,
2996  lvl);
2997 
2998  // then renumber the subdomains by first looking at those
2999  // belonging to subdomain 0, then those of subdomain 1, etc. note
3000  // that the algorithm is stable, i.e. if two dofs i,j have i<j and
3001  // belong to the same subdomain, then they will be in this order
3002  // also after reordering
3003  types::global_dof_index next_free_index = 0;
3004  for (types::subdomain_id level_subdomain = 0;
3005  level_subdomain < n_procs;
3006  ++level_subdomain)
3007  for (types::global_dof_index i = 0; i < n_dofs_on_level; ++i)
3008  if (level_subdomain_association[i] == level_subdomain)
3009  {
3010  Assert(new_dof_indices[i] == numbers::invalid_dof_index,
3011  ExcInternalError());
3012  new_dof_indices[i] = next_free_index;
3013  ++next_free_index;
3014  }
3015 
3016  // we should have numbered all dofs
3017  Assert(next_free_index == n_dofs_on_level, ExcInternalError());
3018  Assert(std::find(new_dof_indices.begin(),
3019  new_dof_indices.end(),
3021  new_dof_indices.end(),
3022  ExcInternalError());
3023  }
3024 
3025  // finally do the renumbering. we can use the sequential
3026  // version of the function because we do things on all
3027  // cells and all cells have their subdomain ids and DoFs
3028  // correctly set
3029  Implementation::renumber_mg_dofs(
3030  new_dof_indices, IndexSet(0), *this->dof_handler, lvl, true);
3031 
3032  // update the number cache. for this, we first have to find the
3033  // level subdomain association for each DoF again following
3034  // renumbering, from which we can then compute the IndexSets of
3035  // locally owned DoFs for all processors. all other fields then
3036  // follow from this
3037  //
3038  // given the way we enumerate degrees of freedom, the locally owned
3039  // ranges must all be contiguous and consecutive. this makes filling
3040  // the IndexSets cheap. an assertion at the top verifies that this
3041  // assumption is true
3042  const std::vector<types::subdomain_id> level_subdomain_association =
3043  get_dof_level_subdomain_association(*this->dof_handler,
3044  n_dofs_on_level,
3045  n_procs,
3046  lvl);
3047 
3048  for (unsigned int i = 1; i < n_dofs_on_level; ++i)
3049  Assert(level_subdomain_association[i] >=
3050  level_subdomain_association[i - 1],
3051  ExcInternalError());
3052 
3053  std::vector<IndexSet> locally_owned_dofs_per_processor(
3054  n_procs, IndexSet(n_dofs_on_level));
3055  {
3056  // we know that the set of subdomain indices is contiguous from
3057  // the assertion above; find the start and end index for each
3058  // processor, taking into account that sometimes a processor
3059  // may not in fact have any DoFs at all. we do the latter
3060  // by just identifying contiguous ranges of level_subdomain_ids
3061  // and filling IndexSets for those subdomains; subdomains
3062  // that don't appear will lead to IndexSets that are simply
3063  // never touched and remain empty as initialized above.
3064  unsigned int start_index = 0;
3065  unsigned int end_index = 0;
3066  while (start_index < n_dofs_on_level)
3067  {
3068  while ((end_index) < n_dofs_on_level &&
3069  (level_subdomain_association[end_index] ==
3070  level_subdomain_association[start_index]))
3071  ++end_index;
3072 
3073  // we've now identified a range of same indices. set that
3074  // range in the corresponding IndexSet
3075  if (end_index > start_index)
3076  {
3077  const unsigned int level_subdomain_owner =
3078  level_subdomain_association[start_index];
3079  locally_owned_dofs_per_processor[level_subdomain_owner]
3080  .add_range(start_index, end_index);
3081  }
3082 
3083  // then move on to thinking about the next range
3084  start_index = end_index;
3085  }
3086  }
3087 
3088  // finally, restore current level subdomain ids
3089  {
3090  typename parallel::shared::Triangulation<dim,
3091  spacedim>::cell_iterator
3092  cell = this->dof_handler->get_triangulation().begin(lvl),
3093  endc = this->dof_handler->get_triangulation().end(lvl);
3094 
3095  for (unsigned int index = 0; cell != endc; ++cell, ++index)
3096  cell->set_level_subdomain_id(saved_level_subdomain_ids[index]);
3097 
3098  // add NumberCache for current level
3099  number_caches.emplace_back(
3100  NumberCache(locally_owned_dofs_per_processor,
3101  this->dof_handler->get_triangulation()
3102  .locally_owned_subdomain()));
3103  }
3104  }
3105 
3106  return number_caches;
3107  }
3108 
3109 
3110 
3111  template <class DoFHandlerType>
3112  NumberCache
3114  const std::vector<types::global_dof_index> &new_numbers) const
3115  {
3116 #ifndef DEAL_II_WITH_MPI
3117  (void)new_numbers;
3118  Assert(false, ExcNotImplemented());
3119  return NumberCache();
3120 #else
3121  const unsigned int dim = DoFHandlerType::dimension;
3122  const unsigned int spacedim = DoFHandlerType::space_dimension;
3123 
3124  // Similar to distribute_dofs() we need to have a special treatment in
3125  // case artificial cells are present.
3127  (dynamic_cast<const parallel::shared::Triangulation<dim, spacedim> *>(
3128  &this->dof_handler->get_triangulation()));
3129  Assert(tr != nullptr, ExcInternalError());
3130 
3131  typename parallel::shared::Triangulation<dim,
3132  spacedim>::active_cell_iterator
3133  cell = this->dof_handler->get_triangulation().begin_active(),
3134  endc = this->dof_handler->get_triangulation().end();
3135  std::vector<types::subdomain_id> current_subdomain_ids(
3136  tr->n_active_cells());
3137  const std::vector<types::subdomain_id> &true_subdomain_ids =
3139  if (tr->with_artificial_cells())
3140  for (unsigned int index = 0; cell != endc; cell++, index++)
3141  {
3142  current_subdomain_ids[index] = cell->subdomain_id();
3143  cell->set_subdomain_id(true_subdomain_ids[index]);
3144  }
3145 
3146  std::vector<types::global_dof_index> global_gathered_numbers(
3147  this->dof_handler->n_dofs(), 0);
3148  // as we call DoFRenumbering::subdomain_wise (*dof_handler) from
3149  // distribute_dofs(), we need to support sequential-like input.
3150  // Distributed-like input from, for example, component_wise renumbering
3151  // is also supported.
3152  if (new_numbers.size() == this->dof_handler->n_dofs())
3153  {
3154  global_gathered_numbers = new_numbers;
3155  }
3156  else
3157  {
3158  Assert(new_numbers.size() ==
3159  this->dof_handler->locally_owned_dofs().n_elements(),
3160  ExcInternalError());
3161  const unsigned int n_cpu =
3163  std::vector<types::global_dof_index> gathered_new_numbers(
3164  this->dof_handler->n_dofs(), 0);
3166  this->dof_handler->get_triangulation()
3167  .locally_owned_subdomain(),
3168  ExcInternalError())
3169 
3170  // gather new numbers among processors into one vector
3171  {
3172  std::vector<types::global_dof_index> new_numbers_copy(
3173  new_numbers);
3174 
3175  // store the number of elements that are to be received from each
3176  // process
3177  std::vector<int> rcounts(n_cpu);
3178 
3179  types::global_dof_index shift = 0;
3180  // set rcounts based on new_numbers:
3181  int cur_count = new_numbers_copy.size();
3182  int ierr = MPI_Allgather(&cur_count,
3183  1,
3184  MPI_INT,
3185  rcounts.data(),
3186  1,
3187  MPI_INT,
3188  tr->get_communicator());
3189  AssertThrowMPI(ierr);
3190 
3191  // compute the displacements (relative to recvbuf)
3192  // at which to place the incoming data from process i
3193  std::vector<int> displacements(n_cpu);
3194  for (unsigned int i = 0; i < n_cpu; i++)
3195  {
3196  displacements[i] = shift;
3197  shift += rcounts[i];
3198  }
3199  Assert(((int)new_numbers_copy.size()) ==
3201  tr->get_communicator())],
3202  ExcInternalError());
3203  ierr = MPI_Allgatherv(new_numbers_copy.data(),
3204  new_numbers_copy.size(),
3205  DEAL_II_DOF_INDEX_MPI_TYPE,
3206  gathered_new_numbers.data(),
3207  rcounts.data(),
3208  displacements.data(),
3209  DEAL_II_DOF_INDEX_MPI_TYPE,
3210  tr->get_communicator());
3211  AssertThrowMPI(ierr);
3212  }
3213 
3214  // put new numbers according to the current
3215  // locally_owned_dofs_per_processor IndexSets
3216  types::global_dof_index shift = 0;
3217  // flag_1 and flag_2 are
3218  // used to control that there is a
3219  // one-to-one relation between old and new DoFs.
3220  std::vector<unsigned int> flag_1(this->dof_handler->n_dofs(), 0);
3221  std::vector<unsigned int> flag_2(this->dof_handler->n_dofs(), 0);
3222  for (unsigned int i = 0; i < n_cpu; i++)
3223  {
3224  const IndexSet iset =
3225  this->dof_handler->locally_owned_dofs_per_processor()[i];
3226  for (types::global_dof_index ind = 0; ind < iset.n_elements();
3227  ind++)
3228  {
3229  const types::global_dof_index target =
3230  iset.nth_index_in_set(ind);
3231  const types::global_dof_index value =
3232  gathered_new_numbers[shift + ind];
3233  Assert(target < this->dof_handler->n_dofs(),
3234  ExcInternalError());
3235  Assert(value < this->dof_handler->n_dofs(),
3236  ExcInternalError());
3237  global_gathered_numbers[target] = value;
3238  flag_1[target]++;
3239  flag_2[value]++;
3240  }
3241  shift += iset.n_elements();
3242  }
3243 
3244  Assert(*std::max_element(flag_1.begin(), flag_1.end()) == 1,
3245  ExcInternalError());
3246  Assert(*std::min_element(flag_1.begin(), flag_1.end()) == 1,
3247  ExcInternalError());
3248  Assert((*std::max_element(flag_2.begin(), flag_2.end())) == 1,
3249  ExcInternalError());
3250  Assert((*std::min_element(flag_2.begin(), flag_2.end())) == 1,
3251  ExcInternalError());
3252  }
3253 
3254  // let the sequential algorithm do its magic; ignore the
3255  // return type, but reconstruct the number cache based on
3256  // which DoFs each process owns
3257  Implementation::renumber_dofs(global_gathered_numbers,
3258  IndexSet(0),
3259  *this->dof_handler,
3260  true);
3261 
3262  const NumberCache number_cache(
3263  DoFTools::locally_owned_dofs_per_subdomain(*this->dof_handler),
3264  this->dof_handler->get_triangulation().locally_owned_subdomain());
3265 
3266  // restore artificial cells
3267  cell = tr->begin_active();
3268  if (tr->with_artificial_cells())
3269  for (unsigned int index = 0; cell != endc; cell++, index++)
3270  cell->set_subdomain_id(current_subdomain_ids[index]);
3271 
3272  return number_cache;
3273 #endif
3274  }
3275 
3276 
3277 
3278  template <class DoFHandlerType>
3279  NumberCache
3281  const unsigned int /*level*/,
3282  const std::vector<types::global_dof_index> & /*new_numbers*/) const
3283  {
3284  // multigrid is not currently implemented for shared triangulations
3285  Assert(false, ExcNotImplemented());
3286 
3287  return NumberCache();
3288  }
3289 
3290 
3291 
3292  /* --------------------- class ParallelDistributed ---------------- */
3293 
3294 #ifdef DEAL_II_WITH_P4EST
3295 
3296  namespace
3297  {
3313  template <int dim>
3314  struct CellDataTransferBuffer
3315  {
3316  std::vector<unsigned int> tree_indices;
3317  std::vector<typename ::internal::p4est::types<dim>::quadrant>
3318  quadrants;
3319  std::vector<::types::global_dof_index> dof_numbers_and_indices;
3320 
3321 
3326  template <class Archive>
3327  void
3328  save(Archive &ar, const unsigned int /*version*/) const
3329  {
3330  // we would like to directly serialize the 'quadrants' vector,
3331  // but the element type is internal to p4est and does not
3332  // know how to serialize itself. consequently, first copy it over
3333  // to an array of bytes, and then serialize that
3334  std::vector<char> quadrants_as_chars(sizeof(quadrants[0]) *
3335  quadrants.size());
3336  if (quadrants_as_chars.size() > 0)
3337  {
3338  Assert(quadrants.data() != nullptr, ExcInternalError());
3339  std::memcpy(quadrants_as_chars.data(),
3340  quadrants.data(),
3341  quadrants_as_chars.size());
3342  }
3343 
3344  // now serialize everything
3345  ar &quadrants_as_chars &tree_indices &dof_numbers_and_indices;
3346  }
3347 
3352  template <class Archive>
3353  void
3354  load(Archive &ar, const unsigned int /*version*/)
3355  {
3356  // undo the copying trick from the 'save' function
3357  std::vector<char> quadrants_as_chars;
3358  ar &quadrants_as_chars &tree_indices &dof_numbers_and_indices;
3359 
3360  if (quadrants_as_chars.size() > 0)
3361  {
3362  quadrants.resize(quadrants_as_chars.size() /
3363  sizeof(quadrants[0]));
3364  std::memcpy(quadrants.data(),
3365  quadrants_as_chars.data(),
3366  quadrants_as_chars.size());
3367  }
3368  else
3369  quadrants.clear();
3370  }
3371 
3372  BOOST_SERIALIZATION_SPLIT_MEMBER()
3373 
3374 
3375 
3379  std::vector<char>
3380  pack_data() const
3381  {
3382  // set up a buffer and then use it as the target of a compressing
3383  // stream into which we serialize the current object
3384  std::vector<char> buffer;
3385  {
3386 # ifdef DEAL_II_WITH_ZLIB
3387  boost::iostreams::filtering_ostream out;
3388  out.push(
3389  boost::iostreams::gzip_compressor(boost::iostreams::gzip_params(
3390  boost::iostreams::gzip::best_compression)));
3391  out.push(boost::iostreams::back_inserter(buffer));
3392 
3393  boost::archive::binary_oarchive archive(out);
3394 
3395  archive << *this;
3396  out.flush();
3397 # else
3398  std::ostringstream out;
3399  boost::archive::binary_oarchive archive(out);
3400  archive << *this;
3401  const std::string &s = out.str();
3402  buffer.reserve(s.size());
3403  buffer.assign(s.begin(), s.end());
3404 # endif
3405  }
3406 
3407  return buffer;
3408  }
3409 
3410 
3416  void
3417  unpack_data(const std::vector<char> &buffer)
3418  {
3419  std::string decompressed_buffer;
3420 
3421  // first decompress the buffer
3422  {
3423 # ifdef DEAL_II_WITH_ZLIB
3424  boost::iostreams::filtering_ostream decompressing_stream;
3425  decompressing_stream.push(boost::iostreams::gzip_decompressor());
3426  decompressing_stream.push(
3427  boost::iostreams::back_inserter(decompressed_buffer));
3428  decompressing_stream.write(buffer.data(), buffer.size());
3429 # else
3430  decompressed_buffer.assign(buffer.begin(), buffer.end());
3431 # endif
3432  }
3433 
3434  // then restore the object from the buffer
3435  std::istringstream in(decompressed_buffer);
3436  boost::archive::binary_iarchive archive(in);
3437 
3438  archive >> *this;
3439  }
3440  };
3441 
3442 
3443 
3444  template <int dim, int spacedim>
3445  void
3446  get_mg_dofindices_recursively(
3448  const typename ::internal::p4est::types<dim>::quadrant
3449  &p4est_cell,
3450  const typename DoFHandler<dim, spacedim>::level_cell_iterator
3451  &dealii_cell,
3452  const typename ::internal::p4est::types<dim>::quadrant
3453  & quadrant,
3454  CellDataTransferBuffer<dim> &cell_data_transfer_buffer)
3455  {
3456  if (internal::p4est::quadrant_is_equal<dim>(p4est_cell, quadrant))
3457  {
3458  // why would somebody request a cell that is not ours?
3459  Assert(dealii_cell->level_subdomain_id() ==
3460  tria.locally_owned_subdomain(),
3461  ExcInternalError());
3462 
3463 
3464  std::vector<::types::global_dof_index> local_dof_indices(
3465  dealii_cell->get_fe().dofs_per_cell);
3466  dealii_cell->get_mg_dof_indices(local_dof_indices);
3467 
3468  cell_data_transfer_buffer.dof_numbers_and_indices.push_back(
3469  dealii_cell->get_fe().dofs_per_cell);
3470  cell_data_transfer_buffer.dof_numbers_and_indices.insert(
3471  cell_data_transfer_buffer.dof_numbers_and_indices.end(),
3472  local_dof_indices.begin(),
3473  local_dof_indices.end());
3474  return; // we are done
3475  }
3476 
3477  if (!dealii_cell->has_children())
3478  return;
3479 
3480  if (!internal::p4est::quadrant_is_ancestor<dim>(p4est_cell, quadrant))
3481  return;
3482 
3483  typename ::internal::p4est::types<dim>::quadrant
3485  internal::p4est::init_quadrant_children<dim>(p4est_cell, p4est_child);
3486 
3487  for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
3488  ++c)
3489  get_mg_dofindices_recursively<dim, spacedim>(
3490  tria,
3491  p4est_child[c],
3492  dealii_cell->child(c),
3493  quadrant,
3494  cell_data_transfer_buffer);
3495  }
3496 
3497 
3498  template <int dim, int spacedim>
3499  void
3500  find_marked_mg_ghost_cells_recursively(
3502  & tria,
3503  const unsigned int tree_index,
3504  const typename DoFHandler<dim, spacedim>::level_cell_iterator
3505  &dealii_cell,
3506  const typename ::internal::p4est::types<dim>::quadrant
3507  &p4est_cell,
3508  std::map<::types::subdomain_id, CellDataTransferBuffer<dim>>
3509  &neighbor_cell_list)
3510  {
3511  // recurse...
3512  if (dealii_cell->has_children())
3513  {
3514  typename ::internal::p4est::types<dim>::quadrant
3516  internal::p4est::init_quadrant_children<dim>(p4est_cell,
3517  p4est_child);
3518 
3519 
3520  for (unsigned int c = 0;
3521  c < GeometryInfo<dim>::max_children_per_cell;
3522  ++c)
3523  find_marked_mg_ghost_cells_recursively<dim, spacedim>(
3524  tria,
3525  tree_index,
3526  dealii_cell->child(c),
3527  p4est_child[c],
3528  neighbor_cell_list);
3529  }
3530 
3531  if (dealii_cell->user_flag_set() &&
3532  dealii_cell->level_subdomain_id() !=
3533  tria.locally_owned_subdomain())
3534  {
3535  neighbor_cell_list[dealii_cell->level_subdomain_id()]
3536  .tree_indices.push_back(tree_index);
3537  neighbor_cell_list[dealii_cell->level_subdomain_id()]
3538  .quadrants.push_back(p4est_cell);
3539  }
3540  }
3541 
3542 
3543  template <int dim, int spacedim>
3544  void
3545  set_mg_dofindices_recursively(
3547  const typename ::internal::p4est::types<dim>::quadrant
3548  &p4est_cell,
3549  const typename DoFHandler<dim, spacedim>::level_cell_iterator
3550  &dealii_cell,
3551  const typename ::internal::p4est::types<dim>::quadrant
3552  & quadrant,
3553  ::types::global_dof_index *dofs)
3554  {
3555  if (internal::p4est::quadrant_is_equal<dim>(p4est_cell, quadrant))
3556  {
3557  Assert(dealii_cell->level_subdomain_id() !=
3558  ::numbers::artificial_subdomain_id,
3559  ExcInternalError());
3560 
3561  // update dof indices of cell
3562  std::vector<::types::global_dof_index> dof_indices(
3563  dealii_cell->get_fe().dofs_per_cell);
3564  dealii_cell->get_mg_dof_indices(dof_indices);
3565 
3566  bool complete = true;
3567  for (unsigned int i = 0; i < dof_indices.size(); ++i)
3568  if (dofs[i] != numbers::invalid_dof_index)
3569  {
3570  Assert((dof_indices[i] == (numbers::invalid_dof_index)) ||
3571  (dof_indices[i] == dofs[i]),
3572  ExcInternalError());
3573  dof_indices[i] = dofs[i];
3574  }
3575  else
3576  complete = false;
3577 
3578  if (!complete)
3579  const_cast<
3580  typename DoFHandler<dim, spacedim>::level_cell_iterator &>(
3581  dealii_cell)
3582  ->set_user_flag();
3583  else
3584  const_cast<
3585  typename DoFHandler<dim, spacedim>::level_cell_iterator &>(
3586  dealii_cell)
3587  ->clear_user_flag();
3588 
3589  const_cast<
3590  typename DoFHandler<dim, spacedim>::level_cell_iterator &>(
3591  dealii_cell)
3592  ->set_mg_dof_indices(dof_indices);
3593  return;
3594  }
3595 
3596  if (!dealii_cell->has_children())
3597  return;
3598 
3599  if (!internal::p4est::quadrant_is_ancestor<dim>(p4est_cell, quadrant))
3600  return;
3601 
3602  typename ::internal::p4est::types<dim>::quadrant
3604  internal::p4est::init_quadrant_children<dim>(p4est_cell, p4est_child);
3605 
3606  for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
3607  ++c)
3608  set_mg_dofindices_recursively<dim, spacedim>(
3609  tria, p4est_child[c], dealii_cell->child(c), quadrant, dofs);
3610  }
3611 
3612 
3613 
3614  template <int dim, int spacedim, class DoFHandlerType>
3615  void
3616  communicate_mg_ghost_cells(
3618  & tria,
3619  DoFHandlerType &dof_handler,
3620  const std::vector<::types::global_dof_index>
3621  &coarse_cell_to_p4est_tree_permutation,
3622  const std::vector<::types::global_dof_index>
3623  &p4est_tree_to_coarse_cell_permutation)
3624  {
3625  // build list of cells to request for each neighbor
3626  std::set<::types::subdomain_id> level_ghost_owners =
3627  tria.level_ghost_owners();
3628  using cellmap_t =
3629  std::map<::types::subdomain_id, CellDataTransferBuffer<dim>>;
3630  cellmap_t neighbor_cell_list;
3631  for (std::set<::types::subdomain_id>::iterator it =
3632  level_ghost_owners.begin();
3633  it != level_ghost_owners.end();
3634  ++it)
3635  neighbor_cell_list.insert(
3636  std::make_pair(*it, CellDataTransferBuffer<dim>()));
3637 
3638  for (typename DoFHandlerType::level_cell_iterator cell =
3639  dof_handler.begin(0);
3640  cell != dof_handler.end(0);
3641  ++cell)
3642  {
3643  typename ::internal::p4est::types<dim>::quadrant
3644  p4est_coarse_cell;
3645  internal::p4est::init_coarse_quadrant<dim>(p4est_coarse_cell);
3646 
3647  find_marked_mg_ghost_cells_recursively<dim, spacedim>(
3648  tria,
3649  coarse_cell_to_p4est_tree_permutation[cell->index()],
3650  cell,
3651  p4est_coarse_cell,
3652  neighbor_cell_list);
3653  }
3654  Assert(level_ghost_owners.size() == neighbor_cell_list.size(),
3655  ExcInternalError());
3656 
3657  //* send our requests:
3658  std::vector<std::vector<char>> sendbuffers(level_ghost_owners.size());
3659  std::vector<MPI_Request> requests(level_ghost_owners.size());
3660 
3661  unsigned int idx = 0;
3662  for (typename cellmap_t::iterator it = neighbor_cell_list.begin();
3663  it != neighbor_cell_list.end();
3664  ++it, ++idx)
3665  {
3666  // pack all the data into the buffer for this recipient
3667  // and send it. keep data around till we can make sure
3668  // that the packet has been received
3669  sendbuffers[idx] = it->second.pack_data();
3670  const int ierr = MPI_Isend(sendbuffers[idx].data(),
3671  sendbuffers[idx].size(),
3672  MPI_BYTE,
3673  it->first,
3674  10101,
3675  tria.get_communicator(),
3676  &requests[idx]);
3677  AssertThrowMPI(ierr);
3678  }
3679 
3680  //* receive requests and reply
3681  std::vector<std::vector<char>> reply_buffers(
3682  level_ghost_owners.size());
3683  std::vector<MPI_Request> reply_requests(level_ghost_owners.size());
3684 
3685  for (unsigned int idx = 0; idx < level_ghost_owners.size(); ++idx)
3686  {
3687  std::vector<char> receive;
3688  CellDataTransferBuffer<dim> cell_data_transfer_buffer;
3689 
3690  MPI_Status status;
3691  int len;
3692  int ierr = MPI_Probe(MPI_ANY_SOURCE,
3693  10101,
3694  tria.get_communicator(),
3695  &status);
3696  AssertThrowMPI(ierr);
3697  ierr = MPI_Get_count(&status, MPI_BYTE, &len);
3698  AssertThrowMPI(ierr);
3699  receive.resize(len);
3700 
3701  char *ptr = receive.data();
3702  ierr = MPI_Recv(ptr,
3703  len,
3704  MPI_BYTE,
3705  status.MPI_SOURCE,
3706  status.MPI_TAG,
3707  tria.get_communicator(),
3708  &status);
3709  AssertThrowMPI(ierr);
3710 
3711  cell_data_transfer_buffer.unpack_data(receive);
3712 
3713  // store the dof indices for each cell
3714  for (unsigned int c = 0;
3715  c < cell_data_transfer_buffer.tree_indices.size();
3716  ++c)
3717  {
3718  typename DoFHandlerType::level_cell_iterator cell(
3719  &dof_handler.get_triangulation(),
3720  0,
3721  p4est_tree_to_coarse_cell_permutation
3722  [cell_data_transfer_buffer.tree_indices[c]],
3723  &dof_handler);
3724 
3725  typename ::internal::p4est::types<dim>::quadrant
3726  p4est_coarse_cell;
3727  internal::p4est::init_coarse_quadrant<dim>(p4est_coarse_cell);
3728 
3729  get_mg_dofindices_recursively<dim, spacedim>(
3730  tria,
3731  p4est_coarse_cell,
3732  cell,
3733  cell_data_transfer_buffer.quadrants[c],
3734  cell_data_transfer_buffer);
3735  }
3736 
3737  // send reply
3738  reply_buffers[idx] = cell_data_transfer_buffer.pack_data();
3739  ierr = MPI_Isend(&(reply_buffers[idx])[0],
3740  reply_buffers[idx].size(),
3741  MPI_BYTE,
3742  status.MPI_SOURCE,
3743  10102,
3744  tria.get_communicator(),
3745  &reply_requests[idx]);
3746  AssertThrowMPI(ierr);
3747  }
3748 
3749  //* finally receive the replies
3750  for (unsigned int idx = 0; idx < level_ghost_owners.size(); ++idx)
3751  {
3752  std::vector<char> receive;
3753  CellDataTransferBuffer<dim> cell_data_transfer_buffer;
3754 
3755  MPI_Status status;
3756  int len;
3757  int ierr = MPI_Probe(MPI_ANY_SOURCE,
3758  10102,
3759  tria.get_communicator(),
3760  &status);
3761  AssertThrowMPI(ierr);
3762  ierr = MPI_Get_count(&status, MPI_BYTE, &len);
3763  AssertThrowMPI(ierr);
3764  receive.resize(len);
3765 
3766  char *ptr = receive.data();
3767  ierr = MPI_Recv(ptr,
3768  len,
3769  MPI_BYTE,
3770  status.MPI_SOURCE,
3771  status.MPI_TAG,
3772  tria.get_communicator(),
3773  &status);
3774  AssertThrowMPI(ierr);
3775 
3776  cell_data_transfer_buffer.unpack_data(receive);
3777  if (cell_data_transfer_buffer.tree_indices.size() == 0)
3778  continue;
3779 
3780  // set the dof indices for each cell
3782  cell_data_transfer_buffer.dof_numbers_and_indices.data();
3783  for (unsigned int c = 0;
3784  c < cell_data_transfer_buffer.tree_indices.size();
3785  ++c, dofs += 1 + dofs[0])
3786  {
3787  typename DoFHandlerType::level_cell_iterator cell(
3788  &tria,
3789  0,
3790  p4est_tree_to_coarse_cell_permutation
3791  [cell_data_transfer_buffer.tree_indices[c]],
3792  &dof_handler);
3793 
3794  typename ::internal::p4est::types<dim>::quadrant
3795  p4est_coarse_cell;
3796  internal::p4est::init_coarse_quadrant<dim>(p4est_coarse_cell);
3797 
3798  Assert(cell->get_fe().dofs_per_cell == dofs[0],
3799  ExcInternalError());
3800 
3801  set_mg_dofindices_recursively<dim, spacedim>(
3802  tria,
3803  p4est_coarse_cell,
3804  cell,
3805  cell_data_transfer_buffer.quadrants[c],
3806  dofs + 1);
3807  }
3808  }
3809 
3810  // complete all sends, so that we can safely destroy the
3811  // buffers.
3812  if (requests.size() > 0)
3813  {
3814  const int ierr = MPI_Waitall(requests.size(),
3815  requests.data(),
3816  MPI_STATUSES_IGNORE);
3817  AssertThrowMPI(ierr);
3818  }
3819  if (reply_requests.size() > 0)
3820  {
3821  const int ierr = MPI_Waitall(reply_requests.size(),
3822  reply_requests.data(),
3823  MPI_STATUSES_IGNORE);
3824  AssertThrowMPI(ierr);
3825  }
3826  }
3827 
3828 
3829 
3830  template <int spacedim>
3831  void
3832  communicate_mg_ghost_cells(
3835  const std::vector<::types::global_dof_index> &,
3836  const std::vector<::types::global_dof_index> &)
3837  {
3838  Assert(false, ExcNotImplemented());
3839  }
3840 
3841 
3842 
3843  template <int spacedim>
3844  void
3845  communicate_mg_ghost_cells(
3848  const std::vector<::types::global_dof_index> &,
3849  const std::vector<::types::global_dof_index> &)
3850  {
3851  Assert(false, ExcNotImplemented());
3852  }
3853 
3854 
3855 
3874  template <int spacedim>
3875  void
3876  communicate_dof_indices_on_marked_cells(
3877  const DoFHandler<1, spacedim> &,
3878  const std::map<unsigned int, std::set<::types::subdomain_id>> &,
3879  const std::vector<::types::global_dof_index> &,
3880  const std::vector<::types::global_dof_index> &)
3881  {
3882  Assert(false, ExcNotImplemented());
3883  }
3884 
3885 
3886 
3887  template <int spacedim>
3888  void
3889  communicate_dof_indices_on_marked_cells(
3891  const std::map<unsigned int, std::set<::types::subdomain_id>> &,
3892  const std::vector<::types::global_dof_index> &,
3893  const std::vector<::types::global_dof_index> &)
3894  {
3895  Assert(false, ExcNotImplemented());
3896  }
3897 
3898 
3899 
3900  template <class DoFHandlerType>
3901  void
3902  communicate_dof_indices_on_marked_cells(
3903  const DoFHandlerType &dof_handler,
3904  const std::map<unsigned int, std::set<::types::subdomain_id>> &,
3905  const std::vector<::types::global_dof_index> &,
3906  const std::vector<::types::global_dof_index> &)
3907  {
3908 # ifndef DEAL_II_WITH_MPI
3909  (void)vertices_with_ghost_neighbors;
3910  Assert(false, ExcNotImplemented());
3911 # else
3912  const unsigned int dim = DoFHandlerType::dimension;
3913  const unsigned int spacedim = DoFHandlerType::space_dimension;
3914 
3915  // define functions that pack data on cells that are ghost cells
3916  // somewhere else, and unpack data on cells where we get information
3917  // from elsewhere
3918  auto pack =
3919  [](const typename DoFHandlerType::active_cell_iterator &cell)
3920  -> boost::optional<std::vector<types::global_dof_index>> {
3921  Assert(cell->is_locally_owned(), ExcInternalError());
3922 
3923  // first see whether we need to do anything at all on this cell.
3924  // this is determined by whether the user_flag is set on the
3925  // cell that indicates that the *complete* set of DoF indices
3926  // has not been sent
3927  if (cell->user_flag_set())
3928  {
3929  // get dof indices for the current cell
3930  std::vector<types::global_dof_index> local_dof_indices(
3931  cell->get_fe().dofs_per_cell);
3932  cell->get_dof_indices(local_dof_indices);
3933 
3934  // now see if there are dof indices that were previously
3935  // unknown. this can only happen in phase 1, and in
3936  // that case we know that the user flag must have been set
3937  //
3938  // in any case, if the cell *is* complete, we do not
3939  // need to send the data any more in the next phase. indicate
3940  // this by removing the user flag
3941  if (std::find(local_dof_indices.begin(),
3942  local_dof_indices.end(),
3944  local_dof_indices.end())
3945  {
3946  Assert(cell->user_flag_set(), ExcInternalError());
3947  }
3948  else
3949  cell->clear_user_flag();
3950 
3951  return local_dof_indices;
3952  }
3953  else
3954  {
3955  // the fact that the user flag wasn't set means that there is
3956  // nothing we need to send that hasn't been sent so far.
3957  // so return an empty array, but also verify that indeed
3958  // the cell is complete
3959 # ifdef DEBUG
3960  std::vector<types::global_dof_index> local_dof_indices(
3961  cell->get_fe().dofs_per_cell);
3962  cell->get_dof_indices(local_dof_indices);
3963 
3964  const bool is_complete =
3965  (std::find(local_dof_indices.begin(),
3966  local_dof_indices.end(),
3968  local_dof_indices.end());
3969  Assert(is_complete, ExcInternalError());
3970 # endif
3971  return boost::optional<std::vector<types::global_dof_index>>();
3972  }
3973  };
3974 
3975  auto unpack =
3976  [](const typename DoFHandlerType::active_cell_iterator &cell,
3977  const std::vector<types::global_dof_index> &received_dof_indices)
3978  -> void {
3979  // this function should only be called on ghost cells, and
3980  // on top of that, only on cells that have not been
3981  // completed -- which we indicate via the user flag.
3982  // check both
3983  Assert(cell->is_ghost(), ExcInternalError());
3984  Assert(cell->user_flag_set(), ExcInternalError());
3985 
3986  // if we just got an incomplete array of DoF indices, then we must
3987  // be in the first ghost exchange and the user flag must have been
3988  // set. we tested that already above.
3989  //
3990  // if we did get a complete array, then we may be in the first
3991  // or second ghost exchange, but in any case we need not exchange
3992  // another time. so delete the user flag
3993  const bool is_complete = (std::find(received_dof_indices.begin(),
3994  received_dof_indices.end(),
3996  received_dof_indices.end());
3997  if (is_complete)
3998  cell->clear_user_flag();
3999 
4000  // in any case, set the DoF indices on this cell. some
4001  // of the ones we received may still be invalid because
4002  // the sending processor did not know them yet, so we
4003  // need to merge the ones we get with those that are
4004  // already set here and may have already been known. for
4005  // those that we already know *and* get, they must obviously
4006  // agree
4007  //
4008  // before getting the local dof indices, we need to update the
4009  // cell dof indices cache because we may have set dof indices
4010  // on a neighboring ghost cell before this one, which may have
4011  // affected the dof indices we know about the current cell
4012  std::vector<types::global_dof_index> local_dof_indices(
4013  cell->get_fe().dofs_per_cell);
4014  cell->update_cell_dof_indices_cache();
4015  cell->get_dof_indices(local_dof_indices);
4016 
4017  for (unsigned int i = 0; i < local_dof_indices.size(); ++i)
4018  if (local_dof_indices[i] == numbers::invalid_dof_index)
4019  local_dof_indices[i] = received_dof_indices[i];
4020  else
4021  // we already know the dof index. check that there
4022  // is no conflict
4023  Assert((received_dof_indices[i] ==
4025  (received_dof_indices[i] == local_dof_indices[i]),
4026  ExcInternalError());
4027 
4028  const_cast<typename DoFHandlerType::active_cell_iterator &>(cell)
4029  ->set_dof_indices(local_dof_indices);
4030  };
4031 
4033  std::vector<types::global_dof_index>,
4034  DoFHandlerType>(dof_handler, pack, unpack);
4035 
4036  // finally update the cell DoF indices caches to make sure
4037  // our internal data structures are consistent
4038  update_all_active_cell_dof_indices_caches(dof_handler);
4039 
4040 
4041  // have a barrier so that sends between two calls to this
4042  // function are not mixed up.
4043  //
4044  // this is necessary because above we just see if there are
4045  // messages and then receive them, without discriminating
4046  // where they come from and whether they were sent in phase
4047  // 1 or 2 (the function is called twice in a row). the need
4048  // for a global communication step like this barrier could
4049  // be avoided by receiving messages specifically from those
4050  // processors from which we expect messages, and by using
4051  // different tags for phase 1 and 2, but the cost of a
4052  // barrier is negligible compared to everything else we do
4053  // here
4054  if (const auto *triangulation = dynamic_cast<
4056  &dof_handler.get_triangulation()))
4057  {
4058  const int ierr = MPI_Barrier(triangulation->get_communicator());
4059  AssertThrowMPI(ierr);
4060  }
4061  else
4062  {
4063  Assert(false,
4064  ExcMessage(
4065  "The function communicate_dof_indices_on_marked_cells() "
4066  "only works with parallel distributed triangulations."));
4067  }
4068 # endif
4069  }
4070 
4071 
4072 
4073  } // namespace
4074 
4075 #endif // DEAL_II_WITH_P4EST
4076 
4077 
4078 
4079  template <class DoFHandlerType>
4081  DoFHandlerType &dof_handler)
4082  : dof_handler(&dof_handler)
4083  {}
4084 
4085 
4086 
4087  template <class DoFHandlerType>
4088  NumberCache
4090  {
4091 #ifndef DEAL_II_WITH_P4EST
4092  Assert(false, ExcNotImplemented());
4093  return NumberCache();
4094 #else
4095  const unsigned int dim = DoFHandlerType::dimension;
4096  const unsigned int spacedim = DoFHandlerType::space_dimension;
4097 
4100  const_cast<::Triangulation<dim, spacedim> *>(
4101  &dof_handler->get_triangulation())));
4102  Assert(triangulation != nullptr, ExcInternalError());
4103 
4104  const unsigned int n_cpus =
4106 
4107 
4108  /*
4109  The following algorithm has a number of stages that are all
4110  documented in the paper that describes the parallel::distributed
4111  functionality:
4112 
4113  1/ locally enumerate dofs on locally owned cells
4114  2/ un-numerate those that are on interfaces with ghost
4115  cells and that we don't own based on the tie-breaking
4116  criterion; re-enumerate the remaining ones. the
4117  end result are that we only enumerate locally owned
4118  DoFs
4119  3/ shift indices so that each processor has a unique
4120  range of indices
4121  4/ for all locally owned cells that are ghost
4122  cells somewhere else, send our own DoF indices
4123  to the appropriate set of other processors
4124  */
4125 
4126  // --------- Phase 1: enumerate dofs on locally owned cells
4127  const ::types::global_dof_index n_initial_local_dofs =
4128  Implementation::distribute_dofs(
4129  triangulation->locally_owned_subdomain(), *dof_handler);
4130 
4131  // --------- Phase 2: un-numerate dofs on interfaces to ghost cells
4132  // that we don't own; re-enumerate the remaining ones
4133 
4134  // start with the identity permutation of indices
4135  std::vector<::types::global_dof_index> renumbering(
4136  n_initial_local_dofs);
4137  for (::types::global_dof_index i = 0; i < renumbering.size(); ++i)
4138  renumbering[i] = i;
4139 
4140  {
4141  std::vector<::types::global_dof_index> local_dof_indices;
4142 
4143  for (auto cell : dof_handler->active_cell_iterators())
4144  if (cell->is_ghost() && (cell->subdomain_id() <
4145  triangulation->locally_owned_subdomain()))
4146  {
4147  // we found a neighboring ghost cell whose subdomain
4148  // is "stronger" than our own subdomain
4149 
4150  // delete all dofs that live there and that we have
4151  // previously assigned a number to (i.e. the ones on
4152  // the interface)
4153  local_dof_indices.resize(cell->get_fe().dofs_per_cell);
4154  cell->get_dof_indices(local_dof_indices);
4155  for (auto &local_dof_index : local_dof_indices)
4156  if (local_dof_index != numbers::invalid_dof_index)
4157  renumbering[local_dof_index] = numbers::invalid_dof_index;
4158  }
4159  }
4160 
4161 
4162  // make the remaining indices consecutive
4163  ::types::global_dof_index n_locally_owned_dofs = 0;
4164  for (auto &new_index : renumbering)
4165  if (new_index != numbers::invalid_dof_index)
4166  new_index = n_locally_owned_dofs++;
4167 
4168  // --------- Phase 3: shift indices so that each processor has a unique
4169  // range of indices
4170  std::vector<::types::global_dof_index>
4171  n_locally_owned_dofs_per_processor(n_cpus);
4172 
4173  const int ierr =
4174  MPI_Allgather(&n_locally_owned_dofs,
4175  1,
4176  DEAL_II_DOF_INDEX_MPI_TYPE,
4177  n_locally_owned_dofs_per_processor.data(),
4178  1,
4179  DEAL_II_DOF_INDEX_MPI_TYPE,
4180  triangulation->get_communicator());
4181  AssertThrowMPI(ierr);
4182 
4183  const ::types::global_dof_index my_shift =
4184  std::accumulate(n_locally_owned_dofs_per_processor.begin(),
4185  n_locally_owned_dofs_per_processor.begin() +
4186  triangulation->locally_owned_subdomain(),
4187  static_cast<::types::global_dof_index>(0));
4188  for (auto &new_index : renumbering)
4189  if (new_index != numbers::invalid_dof_index)
4190  new_index += my_shift;
4191 
4192  // now re-enumerate all dofs to this shifted and condensed
4193  // numbering form. we renumber some dofs as invalid, so
4194  // choose the nocheck-version.
4195  Implementation::renumber_dofs(renumbering,
4196  IndexSet(0),
4197  *dof_handler,
4198  false);
4199 
4200  // now a little bit of housekeeping
4201  const ::types::global_dof_index n_global_dofs =
4202  std::accumulate(n_locally_owned_dofs_per_processor.begin(),
4203  n_locally_owned_dofs_per_processor.end(),
4205 
4206  std::vector<IndexSet> locally_owned_dofs_per_processor(
4207  n_cpus, IndexSet(n_global_dofs));
4208  {
4209  ::types::global_dof_index current_shift = 0;
4210  for (unsigned int i = 0; i < n_cpus; ++i)
4211  {
4212  locally_owned_dofs_per_processor[i].add_range(
4213  current_shift,
4214  current_shift + n_locally_owned_dofs_per_processor[i]);
4215  current_shift += n_locally_owned_dofs_per_processor[i];
4216  }
4217  }
4218  NumberCache number_cache(locally_owned_dofs_per_processor,
4219  triangulation->locally_owned_subdomain());
4220  Assert(number_cache
4221  .locally_owned_dofs_per_processor
4222  [triangulation->locally_owned_subdomain()]
4223  .n_elements() == number_cache.n_locally_owned_dofs,
4224  ExcInternalError());
4225  Assert(
4226  !number_cache
4227  .locally_owned_dofs_per_processor[triangulation
4228  ->locally_owned_subdomain()]
4229  .n_elements() ||
4230  number_cache
4231  .locally_owned_dofs_per_processor[triangulation
4232  ->locally_owned_subdomain()]
4233  .nth_index_in_set(0) == my_shift,
4234  ExcInternalError());
4235 
4236  // this ends the phase where we enumerate degrees of freedom on
4237  // each processor. what is missing is communicating DoF indices
4238  // on ghost cells
4239 
4240  // --------- Phase 4: for all locally owned cells that are ghost
4241  // cells somewhere else, send our own DoF indices
4242  // to the appropriate set of other processors
4243  {
4244  std::vector<bool> user_flags;
4245  triangulation->save_user_flags(user_flags);
4246  triangulation->clear_user_flags();
4247 
4248  // figure out which cells are ghost cells on which we have
4249  // to exchange DoF indices
4250  const std::map<unsigned int, std::set<::types::subdomain_id>>
4251  vertices_with_ghost_neighbors =
4252  triangulation->compute_vertices_with_ghost_neighbors();
4253 
4254  // mark all cells that either have to send data (locally
4255  // owned cells that are adjacent to ghost neighbors in some
4256  // way) or receive data (all ghost cells) via the user flags
4257  for (auto cell : dof_handler->active_cell_iterators())
4258  if (cell->is_locally_owned())
4259  {
4260  for (unsigned int v = 0;
4261  v < GeometryInfo<dim>::vertices_per_cell;
4262  ++v)
4263  if (vertices_with_ghost_neighbors.find(cell->vertex_index(
4264  v)) != vertices_with_ghost_neighbors.end())
4265  {
4266  cell->set_user_flag();
4267  break;
4268  }
4269  }
4270  else if (cell->is_ghost())
4271  cell->set_user_flag();
4272 
4273 
4274 
4275  // Send and receive cells. After this, only the local cells
4276  // are marked, that received new data. This has to be
4277  // communicated in a second communication step.
4278  //
4279  // as explained in the 'distributed' paper, this has to be
4280  // done twice
4281  communicate_dof_indices_on_marked_cells(
4282  *dof_handler,
4283  vertices_with_ghost_neighbors,
4285  triangulation->p4est_tree_to_coarse_cell_permutation);
4286 
4287  communicate_dof_indices_on_marked_cells(
4288  *dof_handler,
4289  vertices_with_ghost_neighbors,
4291  triangulation->p4est_tree_to_coarse_cell_permutation);
4292 
4293  // at this point, we must have taken care of the data transfer
4294  // on all cells we had previously marked. verify this
4295 # ifdef DEBUG
4296  for (auto cell : dof_handler->active_cell_iterators())
4297  Assert(cell->user_flag_set() == false, ExcInternalError());
4298 # endif
4299 
4300  triangulation->load_user_flags(user_flags);
4301  }
4302 
4303 # ifdef DEBUG
4304  // check that we are really done
4305  {
4306  std::vector<::types::global_dof_index> local_dof_indices;
4307 
4308  for (auto cell : dof_handler->active_cell_iterators())
4309  if (!cell->is_artificial())
4310  {
4311  local_dof_indices.resize(cell->get_fe().dofs_per_cell);
4312  cell->get_dof_indices(local_dof_indices);
4313  if (local_dof_indices.end() !=
4314  std::find(local_dof_indices.begin(),
4315  local_dof_indices.end(),
4317  {
4318  if (cell->is_ghost())
4319  {
4320  Assert(false,
4321  ExcMessage(
4322  "A ghost cell ended up with incomplete "
4323  "DoF index information. This should not "
4324  "have happened!"));
4325  }
4326  else
4327  {
4328  Assert(
4329  false,
4330  ExcMessage(
4331  "A locally owned cell ended up with incomplete "
4332  "DoF index information. This should not "
4333  "have happened!"));
4334  }
4335  }
4336  }
4337  }
4338 # endif // DEBUG
4339  return number_cache;
4340 #endif // DEAL_II_WITH_P4EST
4341  }
4342 
4343 
4344 
4345  template <class DoFHandlerType>
4346  std::vector<NumberCache>
4348  {
4349 #ifndef DEAL_II_WITH_P4EST
4350  Assert(false, ExcNotImplemented());
4351  return std::vector<NumberCache>();
4352 #else
4353  const unsigned int dim = DoFHandlerType::dimension;
4354  const unsigned int spacedim = DoFHandlerType::space_dimension;
4355 
4358  const_cast<::Triangulation<dim, spacedim> *>(
4359  &dof_handler->get_triangulation())));
4360  Assert(triangulation != nullptr, ExcInternalError());
4361 
4362  AssertThrow((triangulation->settings &
4364  construct_multigrid_hierarchy),
4365  ExcMessage(
4366  "Multigrid DoFs can only be distributed on a parallel "
4367  "Triangulation if the flag construct_multigrid_hierarchy "
4368  "is set in the constructor."));
4369 
4370 
4371  const unsigned int n_cpus =
4373 
4374  // loop over all levels that exist globally (across all
4375  // processors), even if the current processor does not in fact
4376  // have any cells on that level or if the local part of the
4377  // Triangulation has fewer levels. we need to do this because
4378  // we need to communicate across all processors on all levels
4379  const unsigned int n_levels = triangulation->n_global_levels();
4380  std::vector<NumberCache> number_caches;
4381  number_caches.reserve(n_levels);
4382  for (unsigned int level = 0; level < n_levels; ++level)
4383  {
4384  NumberCache level_number_cache;
4385 
4386  //* 1. distribute on own subdomain
4387  const unsigned int n_initial_local_dofs =
4388  Implementation::distribute_dofs_on_level(
4389  triangulation->locally_owned_subdomain(), *dof_handler, level);
4390 
4391  //* 2. iterate over ghostcells and kill dofs that are not
4392  // owned by us
4393  std::vector<::types::global_dof_index> renumbering(
4394  n_initial_local_dofs);
4395  for (::types::global_dof_index i = 0; i < renumbering.size();
4396  ++i)
4397  renumbering[i] = i;
4398 
4399  if (level < triangulation->n_levels())
4400  {
4401  std::vector<::types::global_dof_index> local_dof_indices;
4402 
4403  typename DoFHandlerType::level_cell_iterator
4404  cell = dof_handler->begin(level),
4405  endc = dof_handler->end(level);
4406 
4407  for (; cell != endc; ++cell)
4408  if (cell->level_subdomain_id() !=
4410  (cell->level_subdomain_id() <
4411  triangulation->locally_owned_subdomain()))
4412  {
4413  // we found a neighboring ghost cell whose
4414  // subdomain is "stronger" than our own
4415  // subdomain
4416 
4417  // delete all dofs that live there and that we
4418  // have previously assigned a number to
4419  // (i.e. the ones on the interface)
4420  local_dof_indices.resize(cell->get_fe().dofs_per_cell);
4421  cell->get_mg_dof_indices(local_dof_indices);
4422  for (unsigned int i = 0; i < cell->get_fe().dofs_per_cell;
4423  ++i)
4424  if (local_dof_indices[i] != numbers::invalid_dof_index)
4425  renumbering[local_dof_indices[i]] =
4427  }
4428  }
4429 
4430  // TODO: make this code simpler with the new constructors of
4431  // NumberCache make indices consecutive
4432  level_number_cache.n_locally_owned_dofs = 0;
4433  for (std::vector<::types::global_dof_index>::iterator it =
4434  renumbering.begin();
4435  it != renumbering.end();
4436  ++it)
4437  if (*it != numbers::invalid_dof_index)
4438  *it = level_number_cache.n_locally_owned_dofs++;
4439 
4440  //* 3. communicate local dofcount and shift ids to make
4441  // them unique
4442  level_number_cache.n_locally_owned_dofs_per_processor.resize(
4443  n_cpus);
4444 
4445  int ierr = MPI_Allgather(
4446  &level_number_cache.n_locally_owned_dofs,
4447  1,
4448  DEAL_II_DOF_INDEX_MPI_TYPE,
4449  &level_number_cache.n_locally_owned_dofs_per_processor[0],
4450  1,
4451  DEAL_II_DOF_INDEX_MPI_TYPE,
4452  triangulation->get_communicator());
4453  AssertThrowMPI(ierr);
4454 
4455  const ::types::global_dof_index shift = std::accumulate(
4456  level_number_cache.n_locally_owned_dofs_per_processor.begin(),
4457  level_number_cache.n_locally_owned_dofs_per_processor.begin() +
4458  triangulation->locally_owned_subdomain(),
4459  static_cast<::types::global_dof_index>(0));
4460  for (std::vector<::types::global_dof_index>::iterator it =
4461  renumbering.begin();
4462  it != renumbering.end();
4463  ++it)
4464  if (*it != numbers::invalid_dof_index)
4465  (*it) += shift;
4466 
4467  // now re-enumerate all dofs to this shifted and condensed
4468  // numbering form. we renumber some dofs as invalid, so
4469  // choose the nocheck-version of the function
4470  //
4471  // of course there is nothing for us to renumber if the
4472  // level we are currently dealing with doesn't even exist
4473  // within the current triangulation, so skip renumbering
4474  // in that case
4475  if (level < triangulation->n_levels())
4476  Implementation::renumber_mg_dofs(
4477  renumbering, IndexSet(0), *dof_handler, level, false);
4478 
4479  // now a little bit of housekeeping
4480  level_number_cache.n_global_dofs = std::accumulate(
4481  level_number_cache.n_locally_owned_dofs_per_processor.begin(),
4482  level_number_cache.n_locally_owned_dofs_per_processor.end(),
4483  static_cast<::types::global_dof_index>(0));
4484 
4485  level_number_cache.locally_owned_dofs =
4486  IndexSet(level_number_cache.n_global_dofs);
4487  level_number_cache.locally_owned_dofs.add_range(
4488  shift, shift + level_number_cache.n_locally_owned_dofs);
4489  level_number_cache.locally_owned_dofs.compress();
4490 
4491  // fill global_dof_indexsets
4492  level_number_cache.locally_owned_dofs_per_processor.resize(n_cpus);
4493  {
4494  ::types::global_dof_index current_shift = 0;
4495  for (unsigned int i = 0; i < n_cpus; ++i)
4496  {
4497  level_number_cache.locally_owned_dofs_per_processor[i] =
4498  IndexSet(level_number_cache.n_global_dofs);
4499  level_number_cache.locally_owned_dofs_per_processor[i]
4500  .add_range(current_shift,
4501  current_shift +
4502  level_number_cache
4503  .n_locally_owned_dofs_per_processor[i]);
4504  current_shift +=
4505  level_number_cache.n_locally_owned_dofs_per_processor[i];
4506  }
4507  }
4508  Assert(level_number_cache
4509  .locally_owned_dofs_per_processor
4510  [triangulation->locally_owned_subdomain()]
4511  .n_elements() == level_number_cache.n_locally_owned_dofs,
4512  ExcInternalError());
4513  Assert(!level_number_cache
4514  .locally_owned_dofs_per_processor
4515  [triangulation->locally_owned_subdomain()]
4516  .n_elements() ||
4517  level_number_cache
4519  [triangulation->locally_owned_subdomain()]
4520  .nth_index_in_set(0) == shift,
4521  ExcInternalError());
4522 
4523  number_caches.emplace_back(level_number_cache);
4524  }
4525 
4526 
4527  //* communicate ghost DoFs
4528  // We mark all ghost cells by setting the user_flag and then request
4529  // these cells from the corresponding owners. As this information
4530  // can be incomplete,
4531  {
4532  std::vector<bool> user_flags;
4533  triangulation->save_user_flags(user_flags);
4534  triangulation->clear_user_flags();
4535 
4536  // mark all ghost cells for transfer
4537  {
4538  typename DoFHandlerType::level_cell_iterator cell,
4539  endc = dof_handler->end();
4540  for (cell = dof_handler->begin(); cell != endc; ++cell)
4541  if (cell->level_subdomain_id() !=
4542  ::numbers::artificial_subdomain_id &&
4543  !cell->is_locally_owned_on_level())
4544  cell->set_user_flag();
4545  }
4546 
4547  // Phase 1. Request all marked cells from corresponding owners. If we
4548  // managed to get every DoF, remove the user_flag, otherwise we
4549  // will request them again in the step below.
4550  communicate_mg_ghost_cells(
4551  *triangulation,
4552  *dof_handler,
4554  triangulation->p4est_tree_to_coarse_cell_permutation);
4555 
4556  // have a barrier so that sends from above and below this
4557  // place are not mixed up.
4558  //
4559  // this is necessary because above we just see if there are
4560  // messages and then receive them, without discriminating
4561  // where they come from and whether they were sent in phase
4562  // 1 or 2 in communicate_mg_ghost_cells() on another
4563  // processor. the need for a global communication step like
4564  // this barrier could be avoided by receiving messages
4565  // specifically from those processors from which we expect
4566  // messages, and by using different tags for phase 1 and 2,
4567  // but the cost of a barrier is negligible compared to
4568  // everything else we do here
4569  const int ierr = MPI_Barrier(triangulation->get_communicator());
4570  AssertThrowMPI(ierr);
4571 
4572  // Phase 2, only request the cells that were not completed
4573  // in Phase 1.
4574  communicate_mg_ghost_cells(
4575  *triangulation,
4576  *dof_handler,
4578  triangulation->p4est_tree_to_coarse_cell_permutation);
4579 
4580 # ifdef DEBUG
4581  // make sure we have removed all flags:
4582  {
4583  typename DoFHandlerType::level_cell_iterator cell,
4584  endc = dof_handler->end();
4585  for (cell = dof_handler->begin(); cell != endc; ++cell)
4586  if (cell->level_subdomain_id() !=
4587  ::numbers::artificial_subdomain_id &&
4588  !cell->is_locally_owned_on_level())
4589  Assert(cell->user_flag_set() == false, ExcInternalError());
4590  }
4591 # endif
4592 
4593  triangulation->load_user_flags(user_flags);
4594  }
4595 
4596 
4597 
4598 # ifdef DEBUG
4599  // check that we are really done
4600  {
4601  std::vector<::types::global_dof_index> local_dof_indices;
4602  typename DoFHandlerType::level_cell_iterator cell,
4603  endc = dof_handler->end();
4604 
4605  for (cell = dof_handler->begin(); cell != endc; ++cell)
4606  if (cell->level_subdomain_id() !=
4607  ::numbers::artificial_subdomain_id)
4608  {
4609  local_dof_indices.resize(cell->get_fe().dofs_per_cell);
4610  cell->get_mg_dof_indices(local_dof_indices);
4611  if (local_dof_indices.end() !=
4612  std::find(local_dof_indices.begin(),
4613  local_dof_indices.end(),
4615  {
4616  Assert(false, ExcMessage("not all DoFs got distributed!"));
4617  }
4618  }
4619  }
4620 # endif // DEBUG
4621 
4622  return number_caches;
4623 
4624 #endif // DEAL_II_WITH_P4EST
4625  }
4626 
4627 
4628  template <class DoFHandlerType>
4629  NumberCache
4631  const std::vector<::types::global_dof_index> &new_numbers) const
4632  {
4633  (void)new_numbers;
4634 
4635  Assert(new_numbers.size() == dof_handler->n_locally_owned_dofs(),
4636  ExcInternalError());
4637 
4638 #ifndef DEAL_II_WITH_P4EST
4639  Assert(false, ExcNotImplemented());
4640  return NumberCache();
4641 #else
4642  const unsigned int dim = DoFHandlerType::dimension;
4643  const unsigned int spacedim = DoFHandlerType::space_dimension;
4644 
4647  const_cast<::Triangulation<dim, spacedim> *>(
4648  &dof_handler->get_triangulation())));
4649  Assert(triangulation != nullptr, ExcInternalError());
4650 
4651 
4652  // First figure out the new set of locally owned DoF indices.
4653  // If we own no DoFs, we still need to go through this function,
4654  // but we can skip this calculation.
4655  //
4656  // The IndexSet::add_indices() function is substantially more
4657  // efficient if the set of indices is already sorted because
4658  // it can then insert ranges instead of individual elements.
4659  // consequently, pre-sort the array of new indices
4660  IndexSet my_locally_owned_new_dof_indices(dof_handler->n_dofs());
4661  if (dof_handler->n_locally_owned_dofs() > 0)
4662  {
4663  std::vector<::types::global_dof_index> new_numbers_sorted =
4664  new_numbers;
4665  std::sort(new_numbers_sorted.begin(), new_numbers_sorted.end());
4666 
4667  my_locally_owned_new_dof_indices.add_indices(
4668  new_numbers_sorted.begin(), new_numbers_sorted.end());
4669  my_locally_owned_new_dof_indices.compress();
4670 
4671  Assert(my_locally_owned_new_dof_indices.n_elements() ==
4672  new_numbers.size(),
4673  ExcInternalError());
4674  }
4675 
4676  // delete all knowledge of DoF indices that are not locally
4677  // owned. we do so by getting DoF indices on cells, checking
4678  // whether they are locally owned, if not, setting them to
4679  // an invalid value, and then setting them again on the current
4680  // cell
4681  //
4682  // DoFs we (i) know about, and (ii) don't own locally must be located
4683  // either on ghost cells, or on the interface between a locally
4684  // owned cell and a ghost cell. In any case, it is sufficient
4685  // to kill them only from the ghost side cell, so loop only over
4686  // ghost cells
4687  {
4688  std::vector<::types::global_dof_index> local_dof_indices;
4689 
4690  for (auto cell : dof_handler->active_cell_iterators())
4691  if (cell->is_ghost())
4692  {
4693  local_dof_indices.resize(cell->get_fe().dofs_per_cell);
4694  cell->get_dof_indices(local_dof_indices);
4695 
4696  for (unsigned int i = 0; i < cell->get_fe().dofs_per_cell; ++i)
4697  // delete a DoF index if it has not already been deleted
4698  // (e.g., by visiting a neighboring cell, if it is on the
4699  // boundary), and if we don't own it
4700  if ((local_dof_indices[i] != numbers::invalid_dof_index) &&
4701  (!dof_handler->locally_owned_dofs().is_element(
4702  local_dof_indices[i])))
4703  local_dof_indices[i] = numbers::invalid_dof_index;
4704 
4705  cell->set_dof_indices(local_dof_indices);
4706  }
4707  }
4708 
4709 
4710  // renumber. Skip when there is nothing to do because we own no DoF.
4711  if (dof_handler->locally_owned_dofs().n_elements() > 0)
4712  Implementation::renumber_dofs(new_numbers,
4713  dof_handler->locally_owned_dofs(),
4714  *dof_handler,
4715  false);
4716 
4717  // communicate newly assigned DoF indices to other processors
4718  // and get the same information for our own ghost cells.
4719  //
4720  // this is the same as phase 4 in the distribute_dofs() algorithm
4721  {
4722  std::vector<bool> user_flags;
4723  triangulation->save_user_flags(user_flags);
4724  triangulation->clear_user_flags();
4725 
4726  // mark all own cells for transfer
4727  for (auto cell : dof_handler->active_cell_iterators())
4728  if (!cell->is_artificial())
4729  cell->set_user_flag();
4730 
4731  // figure out which cells are ghost cells on which we have
4732  // to exchange DoF indices
4733  const std::map<unsigned int, std::set<::types::subdomain_id>>
4734  vertices_with_ghost_neighbors =
4735  triangulation->compute_vertices_with_ghost_neighbors();
4736 
4737 
4738  // Send and receive cells. After this, only the local cells
4739  // are marked, that received new data. This has to be
4740  // communicated in a second communication step.
4741  //
4742  // as explained in the 'distributed' paper, this has to be
4743  // done twice
4744  communicate_dof_indices_on_marked_cells(
4745  *dof_handler,
4746  vertices_with_ghost_neighbors,
4748  triangulation->p4est_tree_to_coarse_cell_permutation);
4749 
4750  communicate_dof_indices_on_marked_cells(
4751  *dof_handler,
4752  vertices_with_ghost_neighbors,
4754  triangulation->p4est_tree_to_coarse_cell_permutation);
4755 
4756  triangulation->load_user_flags(user_flags);
4757  }
4758 
4759  // the last step is to update the NumberCache, including knowing which
4760  // processor owns which DoF index. this requires communication.
4761  //
4762  // this step is substantially more complicated than it is in
4763  // distribute_dofs() because the IndexSets of locally owned DoFs
4764  // after renumbering may not be contiguous any more. for
4765  // distribute_dofs() it was enough to exchange the starting
4766  // indices for each processor and the global number of DoFs,
4767  // but here we actually have to serialize the IndexSet
4768  // objects and shop them across the network.
4769  const unsigned int n_cpus =
4771  std::vector<IndexSet> locally_owned_dofs_per_processor(
4772  n_cpus, IndexSet(dof_handler->n_dofs()));
4773  {
4774  // serialize our own IndexSet
4775  std::vector<char> my_data;
4776  {
4777 # ifdef DEAL_II_WITH_ZLIB
4778 
4779  boost::iostreams::filtering_ostream out;
4780  out.push(
4781  boost::iostreams::gzip_compressor(boost::iostreams::gzip_params(
4782  boost::iostreams::gzip::best_compression)));
4783  out.push(boost::iostreams::back_inserter(my_data));
4784 
4785  boost::archive::binary_oarchive archive(out);
4786 
4787  archive << my_locally_owned_new_dof_indices;
4788  out.flush();
4789 # else
4790  std::ostringstream out;
4791  boost::archive::binary_oarchive archive(out);
4792  archive << my_locally_owned_new_dof_indices;
4793  const std::string &s = out.str();
4794  my_data.reserve(s.size());
4795  my_data.assign(s.begin(), s.end());
4796 # endif
4797  }
4798 
4799  // determine maximum size of IndexSet
4800  const unsigned int max_size =
4801  Utilities::MPI::max(my_data.size(),
4802  triangulation->get_communicator());
4803 
4804  // as the MPI_Allgather call will be reading max_size elements, and
4805  // as this may be past the end of my_data, we need to increase the
4806  // size of the local buffer. This is filled with zeros.
4807  my_data.resize(max_size);
4808 
4809  std::vector<char> buffer(max_size * n_cpus);
4810  const int ierr = MPI_Allgather(my_data.data(),
4811  max_size,
4812  MPI_BYTE,
4813  buffer.data(),
4814  max_size,
4815  MPI_BYTE,
4816  triangulation->get_communicator());
4817  AssertThrowMPI(ierr);
4818 
4819  for (unsigned int i = 0; i < n_cpus; ++i)
4821  triangulation->get_communicator()))
4822  locally_owned_dofs_per_processor[i] =
4823  my_locally_owned_new_dof_indices;
4824  else
4825  {
4826  // copy the data previously received into a stringstream
4827  // object and then read the IndexSet from it
4828  std::string decompressed_buffer;
4829 
4830  // first decompress the buffer
4831  {
4832 # ifdef DEAL_II_WITH_ZLIB
4833 
4834  boost::iostreams::filtering_ostream decompressing_stream;
4835  decompressing_stream.push(
4836  boost::iostreams::gzip_decompressor());
4837  decompressing_stream.push(
4838  boost::iostreams::back_inserter(decompressed_buffer));
4839 
4840  decompressing_stream.write(&buffer[i * max_size], max_size);
4841 # else
4842  decompressed_buffer.assign(&buffer[i * max_size], max_size);
4843 # endif
4844  }
4845 
4846  // then restore the object from the buffer
4847  std::istringstream in(decompressed_buffer);
4848  boost::archive::binary_iarchive archive(in);
4849 
4850  archive >> locally_owned_dofs_per_processor[i];
4851  }
4852  }
4853 
4854  return NumberCache(locally_owned_dofs_per_processor,
4856  triangulation->get_communicator()));
4857 #endif
4858  }
4859 
4860 
4861 
4862  template <class DoFHandlerType>
4863  NumberCache
4865  const unsigned int level,
4866  const std::vector<types::global_dof_index> &new_numbers) const
4867  {
4868  // we only implement the case where the multigrid numbers are
4869  // renumbered within the processor's partition, rather than the most
4870  // general case
4871  const std::vector<IndexSet> &index_sets =
4872  dof_handler->locally_owned_mg_dofs_per_processor(level);
4873 
4874  constexpr int dim = DoFHandlerType::dimension;
4875  constexpr int spacedim = DoFHandlerType::space_dimension;
4877  (dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
4878  &this->dof_handler->get_triangulation()));
4879  Assert(tr != nullptr, ExcInternalError());
4880 
4881 #ifdef DEAL_II_WITH_MPI
4882  const unsigned int my_rank =
4884 
4885 # ifdef DEBUG
4886  for (types::global_dof_index i : new_numbers)
4887  {
4888  Assert(index_sets[my_rank].is_element(i),
4890  "Renumberings that change the locally owned mg dofs "
4891  "partitioning are currently not implemented for "
4892  "the multigrid levels"));
4893  }
4894 # endif
4895 
4896  // we need to access all locally relevant degrees of freedom. we
4897  // use Utilities::MPI::Partitioner for handling the data exchange
4898  // of the new numbers, which is simply the extraction of ghost data
4899  IndexSet relevant_dofs;
4901  level,
4902  relevant_dofs);
4903  std::vector<types::global_dof_index> ghosted_new_numbers(
4904  relevant_dofs.n_elements());
4905  {
4906  Utilities::MPI::Partitioner partitioner(index_sets[my_rank],
4907  relevant_dofs,
4908  tr->get_communicator());
4909  std::vector<types::global_dof_index> temp_array(
4910  partitioner.n_import_indices());
4911  const unsigned int communication_channel = 17;
4912  std::vector<MPI_Request> requests;
4913  partitioner.export_to_ghosted_array_start(
4914  communication_channel,
4915  make_array_view(new_numbers),
4916  make_array_view(temp_array),
4917  ArrayView<types::global_dof_index>(ghosted_new_numbers.data() +
4918  new_numbers.size(),
4919  partitioner.n_ghost_indices()),
4920  requests);
4921  partitioner.export_to_ghosted_array_finish(
4922  ArrayView<types::global_dof_index>(ghosted_new_numbers.data() +
4923  new_numbers.size(),
4924  partitioner.n_ghost_indices()),
4925  requests);
4926 
4927  // we need to fill the indices of the locally owned part into the
4928  // new numbers array. their right position is somewhere in the
4929  // middle of the array, so we first copy the ghosted part from
4930  // smaller ranks to the front, then insert the data in the middle.
4931  unsigned int n_ghosts_on_smaller_ranks = 0;
4932  for (std::pair<unsigned int, unsigned int> t :
4933  partitioner.ghost_targets())
4934  {
4935  if (t.first > my_rank)
4936  break;
4937  n_ghosts_on_smaller_ranks += t.second;
4938  }
4939  if (n_ghosts_on_smaller_ranks > 0)
4940  {
4941  Assert(ghosted_new_numbers.data() != nullptr, ExcInternalError());
4942  std::memmove(ghosted_new_numbers.data(),
4943  ghosted_new_numbers.data() + new_numbers.size(),
4944  sizeof(types::global_dof_index) *
4945  n_ghosts_on_smaller_ranks);
4946  }
4947  if (new_numbers.size() > 0)
4948  {
4949  Assert(new_numbers.data() != nullptr, ExcInternalError());
4950  std::memcpy(ghosted_new_numbers.data() +
4951  n_ghosts_on_smaller_ranks,
4952  new_numbers.data(),
4953  sizeof(types::global_dof_index) * new_numbers.size());
4954  }
4955  }
4956 
4957  // in case we do not own any of the given level (but only some remote
4958  // processor), we do not need to call the renumbering
4959  if (level < this->dof_handler->get_triangulation().n_levels())
4960  Implementation::renumber_mg_dofs(
4961  ghosted_new_numbers, relevant_dofs, *dof_handler, level, true);
4962 #else
4963  (void)new_numbers;
4964  Assert(false, ExcNotImplemented());
4965 #endif
4966 
4967  return NumberCache(
4969  }
4970  } // namespace Policy
4971  } // namespace DoFHandlerImplementation
4972 } // namespace internal
4973 
4974 
4975 
4976 /*-------------- Explicit Instantiations -------------------------------*/
4977 #include "dof_handler_policy.inst"
4978 
4979 
4980 DEAL_II_NAMESPACE_CLOSE
std::vector< MGVertexDoFs > mg_vertex_dofs
Definition: dof_handler.h:1229
virtual NumberCache renumber_mg_dofs(const unsigned int level, const std::vector< types::global_dof_index > &new_numbers) const override
static const unsigned int invalid_unsigned_int
Definition: types.h:173
std::vector< IndexSet > locally_owned_dofs_per_subdomain(const DoFHandlerType &dof_handler)
Definition: dof_tools.cc:1345
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: dof_handler.cc:943
const types::subdomain_id invalid_subdomain_id
Definition: types.h:255
void clear_user_flags()
Definition: tria.cc:11096
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe.cc:942
types::subdomain_id locally_owned_subdomain() const override
Definition: tria_base.cc:335
Task< RT > new_task(const std::function< RT()> &function)
const std::vector< types::subdomain_id > & get_true_subdomain_ids_of_cells() const
Definition: shared_tria.cc:325
void load_user_flags(std::istream &in)
Definition: tria.cc:11156
const unsigned int dofs_per_quad
Definition: fe_base.h:252
size_type n_elements() const
Definition: index_set.h:1743
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe.cc:953
void export_to_ghosted_array_start(const unsigned int communication_channel, const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &temporary_storage, const ArrayView< Number > &ghost_array, std::vector< MPI_Request > &requests) const
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
const Triangulation< dim, spacedim > & get_triangulation() const
size_type size() const
Definition: index_set.h:1611
const unsigned int dofs_per_line
Definition: fe_base.h:246
void extract_locally_relevant_level_dofs(const DoFHandlerType &dof_handler, const unsigned int level, IndexSet &dof_set)
Definition: dof_tools.cc:1185
unsigned int n_active_cells() const
Definition: tria.cc:12509
unsigned long long int global_dof_index
Definition: types.h:72
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe.cc:931
virtual std::vector< NumberCache > distribute_mg_dofs() const override
active_cell_iterator begin_active(const unsigned int level=0) const
typename ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:194
const std::set< types::subdomain_id > & level_ghost_owners() const
Definition: tria_base.cc:353
virtual MPI_Comm get_communicator() const
Definition: tria_base.cc:155
virtual std::vector< NumberCache > distribute_mg_dofs() const override
static::ExceptionBase & ExcMessage(std::string arg1)
virtual std::vector< NumberCache > distribute_mg_dofs() const override
unsigned int subdomain_id
Definition: types.h:43
unsigned int n_cells() const
Definition: tria.cc:12501
const Triangulation< dim, spacedim > & get_triangulation() const
const unsigned int dofs_per_hex
Definition: fe_base.h:258
#define Assert(cond, exc)
Definition: exceptions.h:1227
types::global_dof_index n_dofs() const
void save_user_flags(std::ostream &out) const
Definition: tria.cc:11107
virtual NumberCache renumber_dofs(const std::vector< types::global_dof_index > &new_numbers) const override
virtual NumberCache renumber_dofs(const std::vector< types::global_dof_index > &new_numbers) const override
unsigned int n_locally_owned_dofs() const
unsigned int max_dofs_per_cell(const DoFHandler< dim, spacedim > &dh)
std::vector< types::global_dof_index > n_locally_owned_dofs_per_processor
Definition: number_cache.h:146
virtual unsigned int n_global_levels() const override
Definition: tria_base.cc:133
virtual NumberCache renumber_mg_dofs(const unsigned int level, const std::vector< types::global_dof_index > &new_numbers) const override
const hp::FECollection< dim, spacedim > & get_fe() const
void compress() const
Definition: index_set.h:1619
std::unique_ptr<::internal::DoFHandlerImplementation::DoFFaces< dim > > faces
Definition: dof_handler.h:1249
cell_iterator end() const
Definition: dof_handler.cc:959
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
Definition: hp.h:102
std::vector< std::unique_ptr<::internal::DoFHandlerImplementation::DoFLevel< dim > > > levels
Definition: dof_handler.h:1237
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:69
void add_range(const size_type begin, const size_type end)
Definition: index_set.cc:96
const types::subdomain_id artificial_subdomain_id
Definition: types.h:272
virtual NumberCache renumber_mg_dofs(const unsigned int level, const std::vector< types::global_dof_index > &new_numbers) const override
const std::vector< IndexSet > & locally_owned_mg_dofs_per_processor(const unsigned int level) const
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
const FiniteElement< dim, spacedim > & get_fe(const unsigned int index=0) const
virtual FiniteElementDomination::Domination compare_for_face_domination(const FiniteElement< dim, spacedim > &fe_other) const
Definition: fe.cc:964
hp::FECollection< dim, spacedim > fe_collection
Definition: dof_handler.h:875
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1834
std::vector< IndexSet > locally_owned_dofs_per_processor
Definition: number_cache.h:157
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:80
bool is_element(const size_type index) const
Definition: index_set.h:1676
static::ExceptionBase & ExcNotImplemented()
const hp::FECollection< dim, spacedim > & get_fe_collection() const
Iterator points to a valid object.
const unsigned int dofs_per_vertex
Definition: fe_base.h:240
void run(const std::vector< std::vector< Iterator >> &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
Definition: work_stream.h:1099
void exchange_cell_data_to_ghosts(const MeshType &mesh, const std::function< boost::optional< DataType >(const typename MeshType::active_cell_iterator &)> &pack, const std::function< void(const typename MeshType::active_cell_iterator &, const DataType &)> &unpack)
static unsigned int n_threads()
Definition: table.h:37
typename ActiveSelector::cell_iterator cell_iterator
Definition: dof_handler.h:268
active_cell_iterator begin_active(const unsigned int level=0) const
Definition: tria.cc:11935
typename ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:240
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
const std::vector< IndexSet > & locally_owned_dofs_per_processor() const
IteratorRange< active_cell_iterator > active_cell_iterators() const
virtual NumberCache renumber_dofs(const std::vector< types::global_dof_index > &new_numbers) const override
T max(const T &t, const MPI_Comm &mpi_communicator)
const std::vector< types::subdomain_id > & get_true_level_subdomain_ids_of_cells(const unsigned int level) const
Definition: shared_tria.cc:334
std::vector< types::global_dof_index > vertex_dofs
Definition: dof_handler.h:1223
std::vector< types::global_dof_index > coarse_cell_to_p4est_tree_permutation
Definition: tria.h:1136
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
static::ExceptionBase & ExcInternalError()
virtual std::map< unsigned int, std::set<::types::subdomain_id > > compute_vertices_with_ghost_neighbors() const override
Definition: tria.cc:4474