Reference documentation for deal.II version 9.1.0-pre
mg_transfer_internal.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 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/distributed/tria.h>
18 
19 #include <deal.II/dofs/dof_tools.h>
20 
21 #include <deal.II/fe/fe_tools.h>
22 
23 #include <deal.II/matrix_free/shape_info.h>
24 
25 #include <deal.II/multigrid/mg_transfer_internal.h>
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 namespace internal
30 {
31  namespace MGTransfer
32  {
33  // Internal data structure that is used in the MPI communication in
34  // fill_copy_indices(). It represents an entry in the copy_indices* map,
35  // that associates a level dof index with a global dof index.
36  struct DoFPair
37  {
38  unsigned int level;
40  types::global_dof_index level_dof_index;
41 
42  DoFPair(const unsigned int level,
43  const types::global_dof_index global_dof_index,
44  const types::global_dof_index level_dof_index)
45  : level(level)
46  , global_dof_index(global_dof_index)
47  , level_dof_index(level_dof_index)
48  {}
49 
50  DoFPair()
51  : level(numbers::invalid_unsigned_int)
52  , global_dof_index(numbers::invalid_dof_index)
53  , level_dof_index(numbers::invalid_dof_index)
54  {}
55  };
56 
57 
58 
59  template <int dim, int spacedim>
60  void
61  fill_copy_indices(
62  const ::DoFHandler<dim, spacedim> &mg_dof,
63  const MGConstrainedDoFs * mg_constrained_dofs,
64  std::vector<std::vector<
65  std::pair<types::global_dof_index, types::global_dof_index>>>
66  &copy_indices,
67  std::vector<std::vector<
68  std::pair<types::global_dof_index, types::global_dof_index>>>
69  &copy_indices_global_mine,
70  std::vector<std::vector<
71  std::pair<types::global_dof_index, types::global_dof_index>>>
72  & copy_indices_level_mine,
73  const bool skip_interface_dofs)
74  {
75  // Now we are filling the variables copy_indices*, which are essentially
76  // maps from global to mgdof for each level stored as a std::vector of
77  // pairs. We need to split this map on each level depending on the
78  // ownership of the global and mgdof, so that we later do not access
79  // non-local elements in copy_to/from_mg.
80  // We keep track in the bitfield dof_touched which global dof has been
81  // processed already (on the current level). This is the same as the
82  // multigrid running in serial.
83 
84  // map cpu_index -> vector of data
85  // that will be copied into copy_indices_level_mine
86  std::vector<DoFPair> send_data_temp;
87 
88  const unsigned int n_levels =
89  mg_dof.get_triangulation().n_global_levels();
90  copy_indices.resize(n_levels);
91  copy_indices_global_mine.resize(n_levels);
92  copy_indices_level_mine.resize(n_levels);
93  IndexSet globally_relevant;
94  DoFTools::extract_locally_relevant_dofs(mg_dof, globally_relevant);
95 
96  const unsigned int dofs_per_cell = mg_dof.get_fe().dofs_per_cell;
97  std::vector<types::global_dof_index> global_dof_indices(dofs_per_cell);
98  std::vector<types::global_dof_index> level_dof_indices(dofs_per_cell);
99 
100  for (unsigned int level = 0; level < n_levels; ++level)
101  {
102  std::vector<bool> dof_touched(globally_relevant.n_elements(), false);
103  copy_indices[level].clear();
104  copy_indices_level_mine[level].clear();
105  copy_indices_global_mine[level].clear();
106 
107  typename ::DoFHandler<dim, spacedim>::active_cell_iterator
108  level_cell = mg_dof.begin_active(level);
109  const typename ::DoFHandler<dim, spacedim>::active_cell_iterator
110  level_end = mg_dof.end_active(level);
111 
112  for (; level_cell != level_end; ++level_cell)
113  {
114  if (mg_dof.get_triangulation().locally_owned_subdomain() !=
116  (level_cell->level_subdomain_id() ==
118  level_cell->subdomain_id() ==
120  continue;
121 
122  // get the dof numbers of this cell for the global and the
123  // level-wise numbering
124  level_cell->get_dof_indices(global_dof_indices);
125  level_cell->get_mg_dof_indices(level_dof_indices);
126 
127  for (unsigned int i = 0; i < dofs_per_cell; ++i)
128  {
129  // we need to ignore if the DoF is on a refinement edge
130  // (hanging node)
131  if (skip_interface_dofs && mg_constrained_dofs != nullptr &&
132  mg_constrained_dofs->at_refinement_edge(
133  level, level_dof_indices[i]))
134  continue;
135 
136  types::global_dof_index global_idx =
137  globally_relevant.index_within_set(global_dof_indices[i]);
138  // skip if we did this global dof already (on this or a
139  // coarser level)
140  if (dof_touched[global_idx])
141  continue;
142  bool global_mine = mg_dof.locally_owned_dofs().is_element(
143  global_dof_indices[i]);
144  bool level_mine =
145  mg_dof.locally_owned_mg_dofs(level).is_element(
146  level_dof_indices[i]);
147 
148 
149  if (global_mine && level_mine)
150  {
151  copy_indices[level].emplace_back(global_dof_indices[i],
152  level_dof_indices[i]);
153  }
154  else if (global_mine)
155  {
156  copy_indices_global_mine[level].emplace_back(
157  global_dof_indices[i], level_dof_indices[i]);
158 
159  // send this to the owner of the level_dof:
160  send_data_temp.emplace_back(level,
161  global_dof_indices[i],
162  level_dof_indices[i]);
163  }
164  else
165  {
166  // somebody will send those to me
167  }
168 
169  dof_touched[global_idx] = true;
170  }
171  }
172  }
173 
174  const ::parallel::Triangulation<dim, spacedim> *tria =
175  (dynamic_cast<const parallel::Triangulation<dim, spacedim> *>(
176  &mg_dof.get_triangulation()));
177  AssertThrow(
178  send_data_temp.size() == 0 || tria != nullptr,
179  ExcMessage(
180  "We should only be sending information with a parallel Triangulation!"));
181 
182 #ifdef DEAL_II_WITH_MPI
183  if (tria)
184  {
185  // TODO: Searching the owner for every single DoF becomes quite
186  // inefficient. Please fix this, Timo.
187  // The list of neighbors is symmetric (our neighbors have us as a
188  // neighbor), so we can use it to send and to know how many messages
189  // we will get.
190  const std::set<types::subdomain_id> &neighbors =
191  tria->level_ghost_owners();
192  std::map<int, std::vector<DoFPair>> send_data;
193 
194  // * find owners of the level dofs and insert into send_data
195  // accordingly
196  for (typename std::vector<DoFPair>::iterator dofpair =
197  send_data_temp.begin();
198  dofpair != send_data_temp.end();
199  ++dofpair)
200  {
201  std::set<types::subdomain_id>::iterator it;
202  for (it = neighbors.begin(); it != neighbors.end(); ++it)
203  {
204  if (mg_dof
205  .locally_owned_mg_dofs_per_processor(
206  dofpair->level)[*it]
207  .is_element(dofpair->level_dof_index))
208  {
209  send_data[*it].push_back(*dofpair);
210  break;
211  }
212  }
213  // Is this level dof not owned by any of our neighbors? That would
214  // certainly be a bug!
215  Assert(it != neighbors.end(),
216  ExcMessage("could not find DoF owner."));
217  }
218 
219  // * send
220  std::vector<MPI_Request> requests;
221  {
222  for (std::set<types::subdomain_id>::iterator it = neighbors.begin();
223  it != neighbors.end();
224  ++it)
225  {
226  requests.push_back(MPI_Request());
227  unsigned int dest = *it;
228  std::vector<DoFPair> &data = send_data[dest];
229  // If there is nothing to send, we still need to send a message,
230  // because the receiving end will be waitng. In that case we
231  // just send an empty message.
232  if (data.size())
233  {
234  const int ierr = MPI_Isend(data.data(),
235  data.size() * sizeof(data[0]),
236  MPI_BYTE,
237  dest,
238  71,
239  tria->get_communicator(),
240  &*requests.rbegin());
241  AssertThrowMPI(ierr);
242  }
243  else
244  {
245  const int ierr = MPI_Isend(nullptr,
246  0,
247  MPI_BYTE,
248  dest,
249  71,
250  tria->get_communicator(),
251  &*requests.rbegin());
252  AssertThrowMPI(ierr);
253  }
254  }
255  }
256 
257  // * receive
258  {
259  // We should get one message from each of our neighbors
260  std::vector<DoFPair> receive_buffer;
261  for (unsigned int counter = 0; counter < neighbors.size();
262  ++counter)
263  {
264  MPI_Status status;
265  int len;
266  int ierr = MPI_Probe(MPI_ANY_SOURCE,
267  71,
268  tria->get_communicator(),
269  &status);
270  AssertThrowMPI(ierr);
271  ierr = MPI_Get_count(&status, MPI_BYTE, &len);
272  AssertThrowMPI(ierr);
273 
274  if (len == 0)
275  {
276  ierr = MPI_Recv(nullptr,
277  0,
278  MPI_BYTE,
279  status.MPI_SOURCE,
280  status.MPI_TAG,
281  tria->get_communicator(),
282  &status);
283  AssertThrowMPI(ierr);
284  continue;
285  }
286 
287  int count = len / sizeof(DoFPair);
288  Assert(static_cast<int>(count * sizeof(DoFPair)) == len,
289  ExcInternalError());
290  receive_buffer.resize(count);
291 
292  void *ptr = receive_buffer.data();
293  ierr = MPI_Recv(ptr,
294  len,
295  MPI_BYTE,
296  status.MPI_SOURCE,
297  status.MPI_TAG,
298  tria->get_communicator(),
299  &status);
300  AssertThrowMPI(ierr);
301 
302  for (unsigned int i = 0; i < receive_buffer.size(); ++i)
303  {
304  copy_indices_level_mine[receive_buffer[i].level]
305  .emplace_back(receive_buffer[i].global_dof_index,
306  receive_buffer[i].level_dof_index);
307  }
308  }
309  }
310 
311  // * wait for all MPI_Isend to complete
312  if (requests.size() > 0)
313  {
314  const int ierr = MPI_Waitall(requests.size(),
315  requests.data(),
316  MPI_STATUSES_IGNORE);
317  AssertThrowMPI(ierr);
318  requests.clear();
319  }
320 # ifdef DEBUG
321  // Make sure in debug mode, that everybody sent/received all packages
322  // on this level. If a deadlock occurs here, the list of expected
323  // senders is not computed correctly.
324  const int ierr = MPI_Barrier(tria->get_communicator());
325  AssertThrowMPI(ierr);
326 # endif
327  }
328 #endif
329 
330  // Sort the indices. This will produce more reliable debug output for
331  // regression tests and likely won't hurt performance even in release
332  // mode.
333  std::less<std::pair<types::global_dof_index, types::global_dof_index>>
334  compare;
335  for (unsigned int level = 0; level < copy_indices.size(); ++level)
336  std::sort(copy_indices[level].begin(),
337  copy_indices[level].end(),
338  compare);
339  for (unsigned int level = 0; level < copy_indices_level_mine.size();
340  ++level)
341  std::sort(copy_indices_level_mine[level].begin(),
342  copy_indices_level_mine[level].end(),
343  compare);
344  for (unsigned int level = 0; level < copy_indices_global_mine.size();
345  ++level)
346  std::sort(copy_indices_global_mine[level].begin(),
347  copy_indices_global_mine[level].end(),
348  compare);
349  }
350 
351 
352 
353  // initialize the vectors needed for the transfer (and merge with the
354  // content in copy_indices_global_mine)
355  template <typename Number>
356  void
357  reinit_ghosted_vector(
358  const IndexSet & locally_owned,
359  std::vector<types::global_dof_index> & ghosted_level_dofs,
360  const MPI_Comm & communicator,
361  LinearAlgebra::distributed::Vector<Number> &ghosted_level_vector,
362  std::vector<std::pair<unsigned int, unsigned int>>
363  &copy_indices_global_mine)
364  {
365  std::sort(ghosted_level_dofs.begin(), ghosted_level_dofs.end());
366  IndexSet ghosted_dofs(locally_owned.size());
367  ghosted_dofs.add_indices(ghosted_level_dofs.begin(),
368  std::unique(ghosted_level_dofs.begin(),
369  ghosted_level_dofs.end()));
370  ghosted_dofs.compress();
371 
372  // Add possible ghosts from the previous content in the vector
373  if (ghosted_level_vector.size() == locally_owned.size())
374  {
375  // shift the local number of the copy indices according to the new
376  // partitioner that we are going to use for the vector
377  const auto &part = ghosted_level_vector.get_partitioner();
378  ghosted_dofs.add_indices(part->ghost_indices());
379  for (unsigned int i = 0; i < copy_indices_global_mine.size(); ++i)
380  copy_indices_global_mine[i].second =
381  locally_owned.n_elements() +
382  ghosted_dofs.index_within_set(
383  part->local_to_global(copy_indices_global_mine[i].second));
384  }
385  ghosted_level_vector.reinit(locally_owned, ghosted_dofs, communicator);
386  }
387 
388  // Transform the ghost indices to local index space for the vector
389  inline void
390  copy_indices_to_mpi_local_numbers(
391  const Utilities::MPI::Partitioner & part,
392  const std::vector<types::global_dof_index> &mine,
393  const std::vector<types::global_dof_index> &remote,
394  std::vector<unsigned int> & localized_indices)
395  {
396  localized_indices.resize(mine.size() + remote.size(),
398  for (unsigned int i = 0; i < mine.size(); ++i)
399  if (mine[i] != numbers::invalid_dof_index)
400  localized_indices[i] = part.global_to_local(mine[i]);
401 
402  for (unsigned int i = 0; i < remote.size(); ++i)
403  if (remote[i] != numbers::invalid_dof_index)
404  localized_indices[i + mine.size()] = part.global_to_local(remote[i]);
405  }
406 
407  // given the collection of child cells in lexicographic ordering as seen
408  // from the parent, compute the first index of the given child
409  template <int dim>
410  unsigned int
411  compute_shift_within_children(const unsigned int child,
412  const unsigned int fe_shift_1d,
413  const unsigned int fe_degree)
414  {
415  // we put the degrees of freedom of all child cells in lexicographic
416  // ordering
417  unsigned int c_tensor_index[dim];
418  unsigned int tmp = child;
419  for (unsigned int d = 0; d < dim; ++d)
420  {
421  c_tensor_index[d] = tmp % 2;
422  tmp /= 2;
423  }
424  const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
425  unsigned int factor = 1;
426  unsigned int shift = fe_shift_1d * c_tensor_index[0];
427  for (unsigned int d = 1; d < dim; ++d)
428  {
429  factor *= n_child_dofs_1d;
430  shift = shift + factor * fe_shift_1d * c_tensor_index[d];
431  }
432  return shift;
433  }
434 
435  // puts the indices on the given child cell in lexicographic ordering with
436  // respect to the collection of all child cells as seen from the parent
437  template <int dim>
438  void
439  add_child_indices(
440  const unsigned int child,
441  const unsigned int fe_shift_1d,
442  const unsigned int fe_degree,
443  const std::vector<unsigned int> & lexicographic_numbering,
444  const std::vector<types::global_dof_index> &local_dof_indices,
445  types::global_dof_index * target_indices)
446  {
447  const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
448  const unsigned int shift =
449  compute_shift_within_children<dim>(child, fe_shift_1d, fe_degree);
450  const unsigned int n_components =
451  local_dof_indices.size() / Utilities::fixed_power<dim>(fe_degree + 1);
452  types::global_dof_index *indices = target_indices + shift;
453  const unsigned int n_scalar_cell_dofs =
454  Utilities::fixed_power<dim>(n_child_dofs_1d);
455  for (unsigned int c = 0, m = 0; c < n_components; ++c)
456  for (unsigned int k = 0; k < (dim > 2 ? (fe_degree + 1) : 1); ++k)
457  for (unsigned int j = 0; j < (dim > 1 ? (fe_degree + 1) : 1); ++j)
458  for (unsigned int i = 0; i < (fe_degree + 1); ++i, ++m)
459  {
460  const unsigned int index =
461  c * n_scalar_cell_dofs +
462  k * n_child_dofs_1d * n_child_dofs_1d + j * n_child_dofs_1d +
463  i;
464  Assert(indices[index] == numbers::invalid_dof_index ||
465  indices[index] ==
466  local_dof_indices[lexicographic_numbering[m]],
467  ExcInternalError());
468  indices[index] = local_dof_indices[lexicographic_numbering[m]];
469  }
470  }
471 
472  template <int dim, typename Number>
473  void
474  setup_element_info(ElementInfo<Number> & elem_info,
475  const FiniteElement<1> & fe,
476  const ::DoFHandler<dim> &mg_dof)
477  {
478  // currently, we have only FE_Q and FE_DGQ type elements implemented
479  elem_info.n_components = mg_dof.get_fe().element_multiplicity(0);
480  AssertDimension(Utilities::fixed_power<dim>(fe.dofs_per_cell) *
481  elem_info.n_components,
482  mg_dof.get_fe().dofs_per_cell);
483  AssertDimension(fe.degree, mg_dof.get_fe().degree);
484  elem_info.fe_degree = fe.degree;
485  elem_info.element_is_continuous = fe.dofs_per_vertex > 0;
487 
488  // step 1.2: get renumbering of 1D basis functions to lexicographic
489  // numbers. The distinction according to fe.dofs_per_vertex is to support
490  // both continuous and discontinuous bases.
491  std::vector<unsigned int> renumbering(fe.dofs_per_cell);
492  {
494  renumbering[0] = 0;
495  for (unsigned int i = 0; i < fe.dofs_per_line; ++i)
496  renumbering[i + fe.dofs_per_vertex] =
498  if (fe.dofs_per_vertex > 0)
499  renumbering[fe.dofs_per_cell - fe.dofs_per_vertex] =
500  fe.dofs_per_vertex;
501  }
502 
503  // step 1.3: create a dummy 1D quadrature formula to extract the
504  // lexicographic numbering for the elements
505  std::vector<Point<1>> basic_support_points = fe.get_unit_support_points();
506  Assert(fe.dofs_per_vertex == 0 || fe.dofs_per_vertex == 1,
508  const unsigned int shift = fe.dofs_per_cell - fe.dofs_per_vertex;
509  const unsigned int n_child_dofs_1d =
510  (fe.dofs_per_vertex > 0 ? (2 * fe.dofs_per_cell - 1) :
511  (2 * fe.dofs_per_cell));
512 
513  elem_info.n_child_cell_dofs =
514  elem_info.n_components * Utilities::fixed_power<dim>(n_child_dofs_1d);
515  const Quadrature<1> dummy_quadrature(
516  std::vector<Point<1>>(1, Point<1>()));
518  shape_info.reinit(dummy_quadrature, mg_dof.get_fe(), 0);
519  elem_info.lexicographic_numbering = shape_info.lexicographic_numbering;
520 
521  // step 1.4: get the 1d prolongation matrix and combine from both children
522  elem_info.prolongation_matrix_1d.resize(fe.dofs_per_cell *
523  n_child_dofs_1d);
524 
525  for (unsigned int c = 0; c < GeometryInfo<1>::max_children_per_cell; ++c)
526  for (unsigned int i = 0; i < fe.dofs_per_cell; ++i)
527  for (unsigned int j = 0; j < fe.dofs_per_cell; ++j)
528  elem_info
529  .prolongation_matrix_1d[i * n_child_dofs_1d + j + c * shift] =
530  fe.get_prolongation_matrix(c)(renumbering[j], renumbering[i]);
531  }
532 
533  namespace
534  {
540  void
541  replace(const MGConstrainedDoFs * mg_constrained_dofs,
542  const unsigned int level,
543  std::vector<types::global_dof_index> &dof_indices)
544  {
545  if (mg_constrained_dofs != nullptr &&
546  mg_constrained_dofs->get_level_constraint_matrix(level)
547  .n_constraints() > 0)
548  for (auto &ind : dof_indices)
549  if (mg_constrained_dofs->get_level_constraint_matrix(level)
551  {
552  Assert(mg_constrained_dofs->get_level_constraint_matrix(level)
554  ->size() == 1,
555  ExcInternalError());
556  ind = mg_constrained_dofs->get_level_constraint_matrix(level)
558  ->front()
559  .first;
560  }
561  }
562  } // namespace
563 
564  // Sets up most of the internal data structures of the MGTransferMatrixFree
565  // class
566  template <int dim, typename Number>
567  void
568  setup_transfer(
569  const ::DoFHandler<dim> & mg_dof,
570  const MGConstrainedDoFs * mg_constrained_dofs,
571  ElementInfo<Number> & elem_info,
572  std::vector<std::vector<unsigned int>> &level_dof_indices,
573  std::vector<std::vector<std::pair<unsigned int, unsigned int>>>
574  & parent_child_connect,
575  std::vector<unsigned int> &n_owned_level_cells,
576  std::vector<std::vector<std::vector<unsigned short>>> &dirichlet_indices,
577  std::vector<std::vector<Number>> & weights_on_refined,
578  std::vector<std::vector<std::pair<unsigned int, unsigned int>>>
579  &copy_indices_global_mine,
581  &ghosted_level_vector)
582  {
583  level_dof_indices.clear();
584  parent_child_connect.clear();
585  n_owned_level_cells.clear();
586  dirichlet_indices.clear();
587  weights_on_refined.clear();
588 
589  // we collect all child DoFs of a mother cell together. For faster
590  // tensorized operations, we align the degrees of freedom
591  // lexicographically. We distinguish FE_Q elements and FE_DGQ elements
592 
593  const ::Triangulation<dim> &tria = mg_dof.get_triangulation();
594 
595  // ---------------------------- 1. Extract 1D info about the finite
596  // element step 1.1: create a 1D copy of the finite element from FETools
597  // where we substitute the template argument
598  AssertDimension(mg_dof.get_fe().n_base_elements(), 1);
599  std::string fe_name = mg_dof.get_fe().base_element(0).get_name();
600  {
601  const std::size_t template_starts = fe_name.find_first_of('<');
602  Assert(fe_name[template_starts + 1] ==
603  (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
604  ExcInternalError());
605  fe_name[template_starts + 1] = '1';
606  }
607  const std::unique_ptr<FiniteElement<1>> fe(
608  FETools::get_fe_by_name<1, 1>(fe_name));
609 
610  setup_element_info(elem_info, *fe, mg_dof);
611 
612 
613  // -------------- 2. Extract and match dof indices between child and
614  // parent
615  const unsigned int n_levels = tria.n_global_levels();
616  level_dof_indices.resize(n_levels);
617  parent_child_connect.resize(n_levels - 1);
618  n_owned_level_cells.resize(n_levels - 1);
619  std::vector<std::vector<unsigned int>> coarse_level_indices(n_levels - 1);
620  for (unsigned int level = 0;
621  level < std::min(tria.n_levels(), n_levels - 1);
622  ++level)
623  coarse_level_indices[level].resize(tria.n_raw_cells(level),
625  std::vector<types::global_dof_index> local_dof_indices(
626  mg_dof.get_fe().dofs_per_cell);
627  dirichlet_indices.resize(n_levels - 1);
628 
629  // We use the vectors stored ghosted_level_vector in the base class for
630  // keeping ghosted transfer indices. To avoid keeping two very similar
631  // vectors, we merge them here.
632  if (ghosted_level_vector.max_level() != n_levels - 1)
633  ghosted_level_vector.resize(0, n_levels - 1);
634 
635  for (unsigned int level = n_levels - 1; level > 0; --level)
636  {
637  unsigned int counter = 0;
638  std::vector<types::global_dof_index> global_level_dof_indices;
639  std::vector<types::global_dof_index> global_level_dof_indices_remote;
640  std::vector<types::global_dof_index> ghosted_level_dofs;
641  std::vector<types::global_dof_index> global_level_dof_indices_l0;
642  std::vector<types::global_dof_index> ghosted_level_dofs_l0;
643 
644  // step 2.1: loop over the cells on the coarse side
645  typename ::DoFHandler<dim>::cell_iterator cell,
646  endc = mg_dof.end(level - 1);
647  for (cell = mg_dof.begin(level - 1); cell != endc; ++cell)
648  {
649  // need to look into a cell if it has children and it is locally
650  // owned
651  if (!cell->has_children())
652  continue;
653 
654  bool consider_cell = false;
655  if (tria.locally_owned_subdomain() ==
657  cell->level_subdomain_id() == tria.locally_owned_subdomain())
658  consider_cell = true;
659 
660  // due to the particular way we store DoF indices (via children),
661  // we also need to add the DoF indices for coarse cells where we
662  // own at least one child
663  bool cell_is_remote = !consider_cell;
664  for (unsigned int c = 0;
665  c < GeometryInfo<dim>::max_children_per_cell;
666  ++c)
667  if (cell->child(c)->level_subdomain_id() ==
668  tria.locally_owned_subdomain())
669  {
670  consider_cell = true;
671  break;
672  }
673 
674  if (!consider_cell)
675  continue;
676 
677  // step 2.2: loop through children and append the dof indices to
678  // the appropriate list. We need separate lists for the owned
679  // coarse cell case (which will be part of
680  // restriction/prolongation between level-1 and level) and the
681  // remote case (which needs to store DoF indices for the
682  // operations between level and level+1).
683  AssertDimension(cell->n_children(),
685  std::vector<types::global_dof_index> &next_indices =
686  cell_is_remote ? global_level_dof_indices_remote :
687  global_level_dof_indices;
688  const std::size_t start_index = next_indices.size();
689  next_indices.resize(start_index + elem_info.n_child_cell_dofs,
691  for (unsigned int c = 0;
692  c < GeometryInfo<dim>::max_children_per_cell;
693  ++c)
694  {
695  if (cell_is_remote && cell->child(c)->level_subdomain_id() !=
696  tria.locally_owned_subdomain())
697  continue;
698  cell->child(c)->get_mg_dof_indices(local_dof_indices);
699 
700  replace(mg_constrained_dofs, level, local_dof_indices);
701 
702  const IndexSet &owned_level_dofs =
703  mg_dof.locally_owned_mg_dofs(level);
704  for (unsigned int i = 0; i < local_dof_indices.size(); ++i)
705  if (!owned_level_dofs.is_element(local_dof_indices[i]))
706  ghosted_level_dofs.push_back(local_dof_indices[i]);
707 
708  add_child_indices<dim>(c,
709  fe->dofs_per_cell -
710  fe->dofs_per_vertex,
711  fe->degree,
712  elem_info.lexicographic_numbering,
713  local_dof_indices,
714  &next_indices[start_index]);
715 
716  // step 2.3 store the connectivity to the parent
717  if (cell->child(c)->has_children() &&
718  (tria.locally_owned_subdomain() ==
720  cell->child(c)->level_subdomain_id() ==
721  tria.locally_owned_subdomain()))
722  {
723  const unsigned int child_index =
724  coarse_level_indices[level][cell->child(c)->index()];
725  AssertIndexRange(child_index,
726  parent_child_connect[level].size());
727  unsigned int parent_index = counter;
728  // remote cells, i.e., cells where we work on a further
729  // level but are not treated on the current level, need to
730  // be placed at the end of the list; however, we do not
731  // yet know the exact position in the array, so shift
732  // their parent index by the number of cells so we can set
733  // the correct number after the end of this loop
734  if (cell_is_remote)
735  parent_index =
736  start_index / elem_info.n_child_cell_dofs +
737  tria.n_cells(level);
738  parent_child_connect[level][child_index] =
739  std::make_pair(parent_index, c);
740  AssertIndexRange(mg_dof.get_fe().dofs_per_cell,
741  static_cast<unsigned short>(-1));
742 
743  // set Dirichlet boundary conditions (as a list of
744  // constrained DoFs) for the child
745  if (mg_constrained_dofs != nullptr)
746  for (unsigned int i = 0;
747  i < mg_dof.get_fe().dofs_per_cell;
748  ++i)
749  if (mg_constrained_dofs->is_boundary_index(
750  level,
751  local_dof_indices
752  [elem_info.lexicographic_numbering[i]]))
753  dirichlet_indices[level][child_index].push_back(i);
754  }
755  }
756  if (!cell_is_remote)
757  {
758  AssertIndexRange(static_cast<unsigned int>(cell->index()),
759  coarse_level_indices[level - 1].size());
760  coarse_level_indices[level - 1][cell->index()] = counter++;
761  }
762 
763  // step 2.4: include indices for the coarsest cells. we still
764  // insert the indices as if they were from a child in order to use
765  // the same code (the coarsest level does not matter much in terms
766  // of memory, so we gain in code simplicity)
767  if (level == 1 && !cell_is_remote)
768  {
769  cell->get_mg_dof_indices(local_dof_indices);
770 
771  replace(mg_constrained_dofs, level - 1, local_dof_indices);
772 
773  const IndexSet &owned_level_dofs_l0 =
774  mg_dof.locally_owned_mg_dofs(0);
775  for (unsigned int i = 0; i < local_dof_indices.size(); ++i)
776  if (!owned_level_dofs_l0.is_element(local_dof_indices[i]))
777  ghosted_level_dofs_l0.push_back(local_dof_indices[i]);
778 
779  const std::size_t start_index =
780  global_level_dof_indices_l0.size();
781  global_level_dof_indices_l0.resize(
782  start_index + elem_info.n_child_cell_dofs,
784  add_child_indices<dim>(
785  0,
786  fe->dofs_per_cell - fe->dofs_per_vertex,
787  fe->degree,
788  elem_info.lexicographic_numbering,
789  local_dof_indices,
790  &global_level_dof_indices_l0[start_index]);
791 
792  dirichlet_indices[0].emplace_back();
793  if (mg_constrained_dofs != nullptr)
794  for (unsigned int i = 0; i < mg_dof.get_fe().dofs_per_cell;
795  ++i)
796  if (mg_constrained_dofs->is_boundary_index(
797  0,
798  local_dof_indices[elem_info
799  .lexicographic_numbering[i]]))
800  dirichlet_indices[0].back().push_back(i);
801  }
802  }
803 
804  // step 2.5: store information about the current level and prepare the
805  // Dirichlet indices and parent-child relationship for the next
806  // coarser level
807  AssertDimension(counter * elem_info.n_child_cell_dofs,
808  global_level_dof_indices.size());
809  n_owned_level_cells[level - 1] = counter;
810  dirichlet_indices[level - 1].resize(counter);
811  parent_child_connect[level - 1].resize(
812  counter,
813  std::make_pair(numbers::invalid_unsigned_int,
815 
816  // step 2.6: put the cells with remotely owned parent to the end of
817  // the list (these are needed for the transfer from level to level+1
818  // but not for the transfer from level-1 to level).
819  if (level < n_levels - 1)
820  for (std::vector<std::pair<unsigned int, unsigned int>>::iterator
821  i = parent_child_connect[level].begin();
822  i != parent_child_connect[level].end();
823  ++i)
824  if (i->first >= tria.n_cells(level))
825  {
826  i->first -= tria.n_cells(level);
827  i->first += counter;
828  }
829 
830  // step 2.7: Initialize the ghosted vector
831  const parallel::Triangulation<dim, dim> *ptria =
832  (dynamic_cast<const parallel::Triangulation<dim, dim> *>(&tria));
833  const MPI_Comm communicator =
834  ptria != nullptr ? ptria->get_communicator() : MPI_COMM_SELF;
835 
836  reinit_ghosted_vector(mg_dof.locally_owned_mg_dofs(level),
837  ghosted_level_dofs,
838  communicator,
839  ghosted_level_vector[level],
840  copy_indices_global_mine[level]);
841 
842  copy_indices_to_mpi_local_numbers(
843  *ghosted_level_vector[level].get_partitioner(),
844  global_level_dof_indices,
845  global_level_dof_indices_remote,
846  level_dof_indices[level]);
847  // step 2.8: Initialize the ghosted vector for level 0
848  if (level == 1)
849  {
850  for (unsigned int i = 0; i < parent_child_connect[0].size(); ++i)
851  parent_child_connect[0][i] = std::make_pair(i, 0U);
852 
853  reinit_ghosted_vector(mg_dof.locally_owned_mg_dofs(0),
854  ghosted_level_dofs_l0,
855  communicator,
856  ghosted_level_vector[0],
857  copy_indices_global_mine[0]);
858 
859  copy_indices_to_mpi_local_numbers(
860  *ghosted_level_vector[0].get_partitioner(),
861  global_level_dof_indices_l0,
862  std::vector<types::global_dof_index>(),
863  level_dof_indices[0]);
864  }
865  }
866 
867  // ---------------------- 3. compute weights to make restriction additive
868 
869  const unsigned int n_child_dofs_1d =
870  fe->degree + 1 + fe->dofs_per_cell - fe->dofs_per_vertex;
871 
872  // get the valence of the individual components and compute the weights as
873  // the inverse of the valence
874  weights_on_refined.resize(n_levels - 1);
875  for (unsigned int level = 1; level < n_levels; ++level)
876  {
877  ghosted_level_vector[level] = 0;
878  for (unsigned int c = 0; c < n_owned_level_cells[level - 1]; ++c)
879  for (unsigned int j = 0; j < elem_info.n_child_cell_dofs; ++j)
880  ghosted_level_vector[level].local_element(
881  level_dof_indices[level][elem_info.n_child_cell_dofs * c +
882  j]) += Number(1.);
883  ghosted_level_vector[level].compress(VectorOperation::add);
884  ghosted_level_vector[level].update_ghost_values();
885 
886  std::vector<unsigned int> degree_to_3(n_child_dofs_1d);
887  degree_to_3[0] = 0;
888  for (unsigned int i = 1; i < n_child_dofs_1d - 1; ++i)
889  degree_to_3[i] = 1;
890  degree_to_3.back() = 2;
891 
892  // we only store 3^dim weights because all dofs on a line have the
893  // same valence, and all dofs on a quad have the same valence.
894  weights_on_refined[level - 1].resize(n_owned_level_cells[level - 1] *
895  Utilities::fixed_power<dim>(3));
896  for (unsigned int c = 0; c < n_owned_level_cells[level - 1]; ++c)
897  for (unsigned int k = 0, m = 0; k < (dim > 2 ? n_child_dofs_1d : 1);
898  ++k)
899  for (unsigned int j = 0; j < (dim > 1 ? n_child_dofs_1d : 1); ++j)
900  {
901  unsigned int shift = 9 * degree_to_3[k] + 3 * degree_to_3[j];
902  for (unsigned int i = 0; i < n_child_dofs_1d; ++i, ++m)
903  weights_on_refined[level -
904  1][c * Utilities::fixed_power<dim>(3) +
905  shift + degree_to_3[i]] =
906  Number(1.) /
907  ghosted_level_vector[level].local_element(
908  level_dof_indices[level]
909  [elem_info.n_child_cell_dofs * c + m]);
910  }
911  }
912  }
913 
914  } // namespace MGTransfer
915 } // namespace internal
916 
917 // Explicit instantiations
918 
919 #include "mg_transfer_internal.inst"
920 
921 DEAL_II_NAMESPACE_CLOSE
bool is_boundary_index(const unsigned int level, const types::global_dof_index index) const
void reinit(const size_type size, const bool omit_zeroing_entries=false)
const std::shared_ptr< const Utilities::MPI::Partitioner > & get_partitioner() const
static const unsigned int invalid_unsigned_int
Definition: types.h:173
const std::vector< Point< dim > > & get_unit_support_points() const
Definition: fe.cc:1000
bool at_refinement_edge(const unsigned int level, const types::global_dof_index index) const
const AffineConstraints< double > & get_level_constraint_matrix(const unsigned int level) const
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1366
const types::subdomain_id invalid_subdomain_id
Definition: types.h:255
void reinit(const Quadrature< 1 > &quad, const FiniteElement< dim > &fe_dim, const unsigned int base_element=0)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1407
size_type n_elements() const
Definition: index_set.h:1743
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition: index_set.h:1652
const unsigned int degree
Definition: fe_base.h:313
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
size_type size() const
Definition: index_set.h:1611
const unsigned int dofs_per_line
Definition: fe_base.h:246
Definition: point.h:106
unsigned long long int global_dof_index
Definition: types.h:72
virtual MPI_Comm get_communicator() const
Definition: tria_base.cc:155
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const
Definition: fe.cc:335
static::ExceptionBase & ExcMessage(std::string arg1)
virtual size_type size() const override
#define Assert(cond, exc)
Definition: exceptions.h:1227
void extract_locally_relevant_dofs(const DoFHandlerType &dof_handler, IndexSet &dof_set)
Definition: dof_tools.cc:1143
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
unsigned int global_to_local(const types::global_dof_index global_index) const
const unsigned int dofs_per_cell
Definition: fe_base.h:297
const types::subdomain_id artificial_subdomain_id
Definition: types.h:272
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1443
bool is_identity_constrained(const size_type index) const
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1834
bool is_element(const size_type index) const
Definition: index_set.h:1676
static::ExceptionBase & ExcNotImplemented()
const unsigned int dofs_per_vertex
Definition: fe_base.h:240
const std::vector< std::pair< size_type, number > > * get_constraint_entries(const size_type line) const
std::vector< unsigned int > lexicographic_numbering
Definition: shape_info.h:226
const types::global_dof_index invalid_dof_index
Definition: types.h:188
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
static::ExceptionBase & ExcInternalError()
size_type n_constraints() const