Reference documentation for deal.II version 9.0.0
face_setup_internal.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #ifndef dealii_face_setup_internal_h
18 #define dealii_face_setup_internal_h
19 
20 #include <deal.II/base/utilities.h>
21 #include <deal.II/base/memory_consumption.h>
22 #include <deal.II/grid/tria.h>
23 #include <deal.II/grid/tria_accessor.h>
24 #include <deal.II/matrix_free/task_info.h>
25 #include <deal.II/matrix_free/face_info.h>
26 
27 #include <fstream>
28 
29 
30 DEAL_II_NAMESPACE_OPEN
31 
32 
33 namespace internal
34 {
35  namespace MatrixFreeFunctions
36  {
44  {
46  :
47  n_hanging_faces_smaller_subdomain (0),
48  n_hanging_faces_larger_subdomain (0)
49  {}
50 
51  std::vector<std::pair<CellId,CellId> > shared_faces;
52  unsigned int n_hanging_faces_smaller_subdomain;
53  unsigned int n_hanging_faces_larger_subdomain;
54  };
55 
56 
57 
68  template <int dim>
69  struct FaceSetup
70  {
71  FaceSetup();
72 
79  template <typename MFAddData>
80  void initialize(const ::Triangulation<dim> &triangulation,
81  const MFAddData &additional_data,
82  std::vector<std::pair<unsigned int,unsigned int> > &cell_levels);
83 
90  void
91  generate_faces(const ::Triangulation<dim> &triangulation,
92  const std::vector<std::pair<unsigned int,unsigned int> > &cell_levels,
93  TaskInfo &task_info);
94 
102  create_face(const unsigned int face_no,
103  const typename ::Triangulation<dim>::cell_iterator &cell,
104  const unsigned int number_cell_interior,
105  const typename ::Triangulation<dim>::cell_iterator &neighbor,
106  const unsigned int number_cell_exterior);
107 
108  bool use_active_cells;
109 
114  enum class FaceCategory : char
115  {
116  locally_active_at_boundary,
117  locally_active_done_here,
118  locally_active_done_elsewhere,
119  ghosted,
120  multigrid_refinement_edge
121  };
122 
123  std::vector<FaceCategory> face_is_owned;
124  std::vector<bool> at_processor_boundary;
125  std::vector<unsigned int> cells_close_to_boundary;
126  std::vector<FaceToCellTopology<1> > inner_faces;
127  std::vector<FaceToCellTopology<1> > boundary_faces;
128  std::vector<FaceToCellTopology<1> > inner_ghost_faces;
129  std::vector<FaceToCellTopology<1> > refinement_edge_faces;
130  };
131 
132 
133 
137  template <int vectorization_width>
138  void
139  collect_faces_vectorization
140  (const std::vector<FaceToCellTopology<1> > &faces_in,
141  const std::vector<bool> &hard_vectorization_boundary,
142  std::vector<unsigned int> &face_partition_data,
143  std::vector<FaceToCellTopology<vectorization_width> > &faces_out);
144 
145 
146 
147  /* -------------------------------------------------------------------- */
148 
149 #ifndef DOXYGEN
150 
151  template <int dim>
152  FaceSetup<dim>::FaceSetup()
153  :
154  use_active_cells (true)
155  {}
156 
157 
158 
159  template <int dim>
160  template <typename MFAddData>
161  void
162  FaceSetup<dim>::initialize(const ::Triangulation<dim> &triangulation,
163  const MFAddData &additional_data,
164  std::vector<std::pair<unsigned int,unsigned int> > &cell_levels)
165  {
166  use_active_cells = additional_data.level_mg_handler == numbers::invalid_unsigned_int;
167 
168 #ifdef DEBUG
169  // safety check
170  if (use_active_cells)
171  for (unsigned int i=0; i<cell_levels.size(); ++i)
172  {
173  typename ::Triangulation<dim>::cell_iterator
174  dcell(&triangulation, cell_levels[i].first,
175  cell_levels[i].second);
176  Assert(dcell->active(), ExcInternalError());
177  }
178 #endif
179 
180  // step 1: add ghost cells for those cells that we identify as
181  // interesting
182 
183  at_processor_boundary.resize(cell_levels.size(), false);
184  cells_close_to_boundary.clear();
185  face_is_owned.resize(dim > 1 ? triangulation.n_raw_faces() :
186  triangulation.n_vertices(), FaceCategory::locally_active_done_elsewhere);
187 
188  // go through the mesh and divide the faces on the processor
189  // boundaries as evenly as possible between the processors
190  std::map<types::subdomain_id, FaceIdentifier> inner_faces_at_proc_boundary;
191  if (dynamic_cast<const parallel::Triangulation<dim>*>(&triangulation))
192  {
193  const types::subdomain_id my_domain = triangulation.locally_owned_subdomain();
194  for (unsigned int i=0; i<cell_levels.size(); ++i)
195  {
196  if (i>0 && cell_levels[i] == cell_levels[i-1])
197  continue;
198  typename ::Triangulation<dim>::cell_iterator
199  dcell(&triangulation, cell_levels[i].first,
200  cell_levels[i].second);
201  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
202  {
203  if (dcell->at_boundary(f) && !dcell->has_periodic_neighbor(f))
204  continue;
205  typename ::Triangulation<dim>::cell_iterator
206  neighbor = dcell->neighbor_or_periodic_neighbor(f);
207 
208  // faces at hanging nodes are always treated by the processor
209  // who owns the element on the fine side. but we need to count
210  // the number of inner faces in order to balance the remaining
211  // faces properly
212  const CellId id_mine = dcell->id();
213  if (use_active_cells && neighbor->has_children())
214  for (unsigned int c=0; c<dcell->face(f)->n_children(); ++c)
215  {
216  typename ::Triangulation<dim>::cell_iterator
217  neighbor_c = dcell->at_boundary(f) ?
218  dcell->periodic_neighbor_child_on_subface(f, c) :
219  dcell->neighbor_child_on_subface(f, c);
220  const types::subdomain_id neigh_domain = neighbor_c->subdomain_id();
221  if (my_domain < neigh_domain)
222  inner_faces_at_proc_boundary[neigh_domain].n_hanging_faces_larger_subdomain++;
223  else if (my_domain > neigh_domain)
224  inner_faces_at_proc_boundary[neigh_domain].n_hanging_faces_smaller_subdomain++;
225  }
226  else
227  {
228  const types::subdomain_id neigh_domain = use_active_cells ?
229  neighbor->subdomain_id() :
230  neighbor->level_subdomain_id();
231  if (neighbor->level() < dcell->level() &&
232  use_active_cells)
233  {
234  if (my_domain < neigh_domain)
235  inner_faces_at_proc_boundary[neigh_domain].n_hanging_faces_smaller_subdomain++;
236  else if (my_domain > neigh_domain)
237  inner_faces_at_proc_boundary[neigh_domain].n_hanging_faces_larger_subdomain++;
238  }
239  else if (neighbor->level() == dcell->level() &&
240  my_domain != neigh_domain)
241  {
242  // always list the cell whose owner has the lower
243  // subdomain id first. this applies to both processors
244  // involved, so both processors will generate the same
245  // list that we will later order
246  const CellId id_neigh = neighbor->id();
247  if (my_domain < neigh_domain)
248  inner_faces_at_proc_boundary[neigh_domain].shared_faces.
249  emplace_back(id_mine, id_neigh);
250  else
251  inner_faces_at_proc_boundary[neigh_domain].shared_faces.
252  emplace_back(id_neigh, id_mine);
253  }
254  }
255  }
256  }
257 
258  // sort the cell ids related to each neighboring processor. This
259  // algorithm is symmetric so every processor combination should
260  // arrive here and no deadlock should be possible
261  for (std::map<types::subdomain_id, FaceIdentifier>::iterator it
262  = inner_faces_at_proc_boundary.begin();
263  it != inner_faces_at_proc_boundary.end(); ++it)
264  {
265  Assert(it->first != my_domain,
266  ExcInternalError("Should not send info to myself"));
267  std::sort(it->second.shared_faces.begin(), it->second.shared_faces.end());
268  it->second.shared_faces.erase(std::unique(it->second.shared_faces.begin(),
269  it->second.shared_faces.end()),
270  it->second.shared_faces.end());
271 
272  // safety check: both involved processors should see the same list
273  // because the pattern of ghosting is symmetric. We test this by
274  // looking at the length of the lists of faces
275 #if defined(DEAL_II_WITH_MPI) && defined(DEBUG)
276  MPI_Comm comm = MPI_COMM_SELF;
277  if (const parallel::Triangulation<dim> *ptria =
278  dynamic_cast<const parallel::Triangulation<dim> *>(&triangulation))
279  comm = ptria->get_communicator();
280 
281  MPI_Status status;
282  unsigned int mysize = it->second.shared_faces.size();
283  unsigned int othersize = numbers::invalid_unsigned_int;
284  MPI_Sendrecv(&mysize, 1, MPI_UNSIGNED, it->first, 600+my_domain,
285  &othersize, 1, MPI_UNSIGNED, it->first, 600+it->first,
286  comm, &status);
287  AssertDimension(mysize, othersize);
288  mysize = it->second.n_hanging_faces_smaller_subdomain;
289  MPI_Sendrecv(&mysize, 1, MPI_UNSIGNED, it->first, 700+my_domain,
290  &othersize, 1, MPI_UNSIGNED, it->first, 700+it->first,
291  comm, &status);
292  AssertDimension(mysize, othersize);
293  mysize = it->second.n_hanging_faces_larger_subdomain;
294  MPI_Sendrecv(&mysize, 1, MPI_UNSIGNED, it->first, 800+my_domain,
295  &othersize, 1, MPI_UNSIGNED, it->first, 800+it->first,
296  comm, &status);
297  AssertDimension(mysize, othersize);
298 #endif
299 
300  // Arrange the face "ownership" such that cells that are access
301  // by more than one face (think of a cell in a corner) get
302  // ghosted. This arrangement has the advantage that we need to
303  // send less data because the same data is used twice. The
304  // strategy applied here is to ensure the same order of face
305  // pairs on both processors that share some faces, and make the
306  // same decision on both sides.
307 
308  // Create a vector with cell ids sorted over the processor with
309  // the larger rank. In the code below we need to be able to
310  // identify the same cell once for the processor with higher
311  // rank and once for the processor with the lower rank. The
312  // format for the processor with the higher rank is already
313  // contained in `shared_faces`, whereas we need a copy that we
314  // sort differently for the other way around.
315  std::vector<std::tuple<CellId,CellId,unsigned int> > other_range(it->second.shared_faces.size());
316  for (unsigned int i=0; i<other_range.size(); ++i)
317  other_range[i] = std::make_tuple(it->second.shared_faces[i].second,
318  it->second.shared_faces[i].first,
319  i);
320  std::sort(other_range.begin(), other_range.end());
321 
322  // the vector 'assignment' sets whether a particular cell
323  // appears more often and acts as a pre-selection of the rank. A
324  // value of 1 means that the process with the higher rank gets
325  // those faces, a value -1 means that the process with the lower
326  // rank gets it, whereas a value 0 means that the decision can
327  // be made in an arbitrary way.
328  unsigned int n_faces_lower_proc = 0, n_faces_higher_proc = 0;
329  std::vector<char> assignment(other_range.size(), 0);
330  if (it->second.shared_faces.size() > 0)
331  {
332  // identify faces that go to the processor with the higher
333  // rank
334  unsigned int count = 0;
335  for (unsigned int i=1; i<it->second.shared_faces.size(); ++i)
336  if (it->second.shared_faces[i].first ==
337  it->second.shared_faces[i-1-count].first)
338  ++count;
339  else
340  {
341  AssertThrow(count < 2*dim, ExcInternalError());
342  if (count > 0)
343  {
344  for (unsigned int k=0; k<=count; ++k)
345  assignment[i-1-k] = 1;
346  n_faces_higher_proc += count+1;
347  }
348  count = 0;
349  }
350 
351  // identify faces that definitely go to the processor with
352  // the lower rank - this must use the sorting of CellId
353  // variables from the processor with the higher rank, i.e.,
354  // other_range rather than `shared_faces`.
355  count = 0;
356  for (unsigned int i=1; i<other_range.size(); ++i)
357  if (std::get<0>(other_range[i]) ==
358  std::get<0>(other_range[i-1-count]))
359  ++count;
360  else
361  {
362  AssertThrow(count < 2*dim, ExcInternalError());
363  if (count > 0)
364  {
365  for (unsigned int k=0; k<=count; ++k)
366  {
367  Assert(it->second.shared_faces[std::get<2>(other_range[i-1])].second ==
368  it->second.shared_faces[std::get<2>(other_range[i-1-k])].second,
369  ExcInternalError());
370  // only assign to -1 if higher rank was not
371  // yet set
372  if (assignment[std::get<2>(other_range[i-1-k])] == 0)
373  {
374  assignment[std::get<2>(other_range[i-1-k])] = -1;
375  ++n_faces_lower_proc;
376  }
377  }
378  }
379  count = 0;
380  }
381  }
382 
383 
384  // divide the faces evenly between the two processors. the
385  // processor with small rank takes the first half, the processor
386  // with larger rank the second half. Adjust for the hanging
387  // faces that always get assigned to one side, and the faces we
388  // have already assigned due to the criterion above
389  n_faces_lower_proc += it->second.n_hanging_faces_smaller_subdomain;
390  n_faces_higher_proc += it->second.n_hanging_faces_larger_subdomain;
391  const unsigned int n_total_faces_at_proc_boundary =
392  (it->second.shared_faces.size() +
393  it->second.n_hanging_faces_smaller_subdomain +
394  it->second.n_hanging_faces_larger_subdomain);
395  unsigned int split_index = n_total_faces_at_proc_boundary/2;
396  if (split_index < n_faces_lower_proc)
397  split_index = 0;
398  else if (split_index < n_total_faces_at_proc_boundary -
399  n_faces_higher_proc)
400  split_index -= n_faces_lower_proc;
401  else
402  split_index = n_total_faces_at_proc_boundary - n_faces_higher_proc - n_faces_lower_proc;
403 
404  // make sure the splitting is consistent between both sides
405 #if defined(DEAL_II_WITH_MPI) && defined(DEBUG)
406  MPI_Sendrecv(&split_index, 1, MPI_UNSIGNED, it->first, 900+my_domain,
407  &othersize, 1, MPI_UNSIGNED, it->first, 900+it->first,
408  comm, &status);
409  AssertDimension(split_index, othersize);
410  MPI_Sendrecv(&n_faces_lower_proc, 1, MPI_UNSIGNED, it->first, 1000+my_domain,
411  &othersize, 1, MPI_UNSIGNED, it->first, 1000+it->first,
412  comm, &status);
413  AssertDimension(n_faces_lower_proc, othersize);
414  MPI_Sendrecv(&n_faces_higher_proc, 1, MPI_UNSIGNED, it->first, 1100+my_domain,
415  &othersize, 1, MPI_UNSIGNED, it->first, 1100+it->first,
416  comm, &status);
417  AssertDimension(n_faces_higher_proc, othersize);
418 #endif
419 
420  // collect the faces on both sides
421  std::vector<std::pair<CellId,CellId> > owned_faces_lower, owned_faces_higher;
422  for (unsigned int i=0; i<assignment.size(); ++i)
423  if (assignment[i] < 0)
424  owned_faces_lower.push_back(it->second.shared_faces[i]);
425  else if (assignment[i] > 0)
426  owned_faces_higher.push_back(it->second.shared_faces[i]);
427  AssertIndexRange(split_index, it->second.shared_faces.size() + 1 -
428  owned_faces_lower.size() - owned_faces_higher.size());
429 
430  unsigned int i=0, c=0;
431  for (; i<assignment.size() && c < split_index; ++i)
432  if (assignment[i] == 0)
433  {
434  owned_faces_lower.push_back(it->second.shared_faces[i]);
435  ++c;
436  }
437  for ( ; i<assignment.size(); ++i)
438  if (assignment[i] == 0)
439  {
440  owned_faces_higher.push_back(it->second.shared_faces[i]);
441  }
442 
443 #ifdef DEBUG
444  // check consistency of faces on both sides
445  std::vector<std::pair<CellId,CellId> > check_faces;
446  check_faces.insert(check_faces.end(), owned_faces_lower.begin(),
447  owned_faces_lower.end());
448  check_faces.insert(check_faces.end(), owned_faces_higher.begin(),
449  owned_faces_higher.end());
450  std::sort(check_faces.begin(), check_faces.end());
451  AssertDimension(check_faces.size(), it->second.shared_faces.size());
452  for (unsigned int i=0; i<check_faces.size(); ++i)
453  Assert(check_faces[i] == it->second.shared_faces[i], ExcInternalError());
454 #endif
455 
456  // now only set half of the faces as the ones to keep
457  if (my_domain < it->first)
458  it->second.shared_faces.swap(owned_faces_lower);
459  else
460  it->second.shared_faces.swap(owned_faces_higher);
461 
462  std::sort(it->second.shared_faces.begin(), it->second.shared_faces.end());
463  }
464  }
465 
466  // fill in the additional cells that we need access to via ghosting to
467  // cell_levels
468  std::set<std::pair<unsigned int, unsigned int> > ghost_cells;
469  for (unsigned int i=0; i<cell_levels.size(); ++i)
470  {
471  typename ::Triangulation<dim>::cell_iterator
472  dcell(&triangulation, cell_levels[i].first,
473  cell_levels[i].second);
474  if (use_active_cells)
475  Assert(dcell->active(), ExcNotImplemented());
476  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
477  {
478  if (dcell->at_boundary(f) && !dcell->has_periodic_neighbor(f))
479  face_is_owned[dcell->face(f)->index()] = FaceCategory::locally_active_at_boundary;
480 
481  // treat boundaries of cells of different refinement level
482  // inside the domain in case of multigrid separately
483  else if ((dcell->at_boundary(f) == false ||
484  dcell->has_periodic_neighbor(f)) &&
485  additional_data.level_mg_handler != numbers::invalid_unsigned_int
486  &&
487  dcell->neighbor_or_periodic_neighbor(f)->level() < dcell->level())
488  {
489  face_is_owned[dcell->face(f)->index()] = FaceCategory::multigrid_refinement_edge;
490  }
491  else
492  {
493  typename ::Triangulation<dim>::cell_iterator neighbor =
494  dcell->neighbor_or_periodic_neighbor(f);
495 
496  // neighbor is refined -> face will be treated by neighbor
497  if (use_active_cells && neighbor->has_children() &&
498  additional_data.hold_all_faces_to_owned_cells == false)
499  continue;
500 
501  bool add_to_ghost = false;
502  const types::subdomain_id
503  id1 = use_active_cells ? dcell->subdomain_id() : dcell->level_subdomain_id(),
504  id2 = use_active_cells ? (neighbor->has_children() ?
505  dcell->neighbor_child_on_subface(f,0)->subdomain_id() :
506  neighbor->subdomain_id()) :
507  neighbor->level_subdomain_id();
508 
509  // Check whether the current face should be processed
510  // locally (instead of being processed from the other
511  // side). We process a face locally when we are more refined
512  // (in the active cell case) or when the face is listed in
513  // the `shared_faces` data structure that we built above.
514  if ((id1 == id2 && (use_active_cells == false ||
515  neighbor->has_children() == false)) ||
516  dcell->level() > neighbor->level() ||
517  std::binary_search(inner_faces_at_proc_boundary[id2].shared_faces.begin(),
518  inner_faces_at_proc_boundary[id2].shared_faces.end(),
519  std::make_pair(id1<id2 ? dcell->id() : neighbor->id(),
520  id1<id2 ? neighbor->id() : dcell->id())))
521  {
522  face_is_owned[dcell->face(f)->index()] = FaceCategory::locally_active_done_here;
523  if (dcell->level() == neighbor->level())
524  face_is_owned[neighbor->face(dcell->has_periodic_neighbor(f) ?
525  dcell->periodic_neighbor_face_no(f) :
526  dcell->neighbor_face_no(f))->index()]
527  = FaceCategory::locally_active_done_here;
528 
529  // If neighbor is a ghost element (i.e. dcell->subdomain_id
530  // ! dcell->neighbor(f)->subdomain_id()), we need to add its
531  // index into cell level list.
532  if (use_active_cells)
533  add_to_ghost = (dcell->subdomain_id() !=
534  neighbor->subdomain_id());
535  else
536  add_to_ghost = (dcell->level_subdomain_id() !=
537  neighbor->level_subdomain_id());
538  }
539  else if (additional_data.hold_all_faces_to_owned_cells == false)
540  {
541  // mark the cell to be close to the boundary
542  cells_close_to_boundary.emplace_back(i);
543  }
544  else
545  {
546  // add all cells to ghost layer...
547  face_is_owned[dcell->face(f)->index()] = FaceCategory::ghosted;
548  if (use_active_cells)
549  {
550  if (neighbor->has_children())
551  for (unsigned int s=0; s<dcell->face(f)->n_children(); ++s)
552  if (dcell->at_boundary(f))
553  {
554  if (dcell->periodic_neighbor_child_on_subface(f,s)->subdomain_id() !=
555  dcell->subdomain_id())
556  add_to_ghost = true;
557  }
558  else
559  {
560  if (dcell->neighbor_child_on_subface(f,s)->subdomain_id() !=
561  dcell->subdomain_id())
562  add_to_ghost = true;
563  }
564  else
565  add_to_ghost = (dcell->subdomain_id() !=
566  neighbor->subdomain_id());
567  }
568  else
569  add_to_ghost = (dcell->level_subdomain_id() !=
570  neighbor->level_subdomain_id());
571  }
572 
573  if (add_to_ghost)
574  {
575  ghost_cells.insert
576  (std::pair<unsigned int,unsigned int>
577  (neighbor->level(), neighbor->index()));
578  at_processor_boundary[i] = true;
579  }
580  }
581  }
582  }
583 
584  // step 2: append the ghost cells at the end of the locally owned
585  // cells
586  for (std::set<std::pair<unsigned int, unsigned int> >::iterator
587  it=ghost_cells.begin(); it!=ghost_cells.end(); ++it)
588  cell_levels.push_back(*it);
589 
590  // step 3: clean up the cells close to the boundary
591  std::sort(cells_close_to_boundary.begin(), cells_close_to_boundary.end());
592  cells_close_to_boundary.erase(std::unique(cells_close_to_boundary.begin(),
593  cells_close_to_boundary.end()),
594  cells_close_to_boundary.end());
595  std::vector<unsigned int> final_cells;
596  final_cells.reserve(cells_close_to_boundary.size());
597  for (unsigned int i=0; i<cells_close_to_boundary.size(); ++i)
598  if (at_processor_boundary[cells_close_to_boundary[i]] == false)
599  final_cells.push_back(cells_close_to_boundary[i]);
600  cells_close_to_boundary = std::move(final_cells);
601  }
602 
603 
604 
605  template <int dim>
606  void
608  ::generate_faces(const ::Triangulation<dim> &triangulation,
609  const std::vector<std::pair<unsigned int,unsigned int> > &cell_levels,
610  TaskInfo &task_info)
611  {
612  // step 1: create the inverse map between cell iterators and the
613  // cell_level_index field
614  std::map<std::pair<unsigned int,unsigned int>, unsigned int>
615  map_to_vectorized;
616  for (unsigned int cell=0; cell<cell_levels.size(); ++cell)
617  if (cell == 0 || cell_levels[cell] != cell_levels[cell-1])
618  {
619  typename ::Triangulation<dim>::cell_iterator dcell
620  (&triangulation, cell_levels[cell].first, cell_levels[cell].second);
621  std::pair<unsigned int,unsigned int> level_index(dcell->level(),
622  dcell->index());
623  map_to_vectorized[level_index] = cell;
624  }
625 
626  // step 2: fill the information about inner faces and boundary faces
627  const unsigned int vectorization_length = task_info.vectorization_length;
628  task_info.face_partition_data.resize(task_info.cell_partition_data.size()-1, 0);
629  task_info.boundary_partition_data.resize(task_info.cell_partition_data.size()-1, 0);
630  std::vector<unsigned char> face_visited(face_is_owned.size(), 0);
631  for (unsigned int partition=0; partition<task_info.cell_partition_data.size()-2; ++partition)
632  {
633  unsigned int boundary_counter = 0;
634  unsigned int inner_counter = 0;
635  for (unsigned int cell=
636  task_info.cell_partition_data[partition]*vectorization_length;
637  cell<task_info.cell_partition_data[partition+1]*vectorization_length;
638  ++cell)
639  if (cell == 0 || cell_levels[cell] != cell_levels[cell-1])
640  {
641  typename ::Triangulation<dim>::cell_iterator dcell
642  (&triangulation, cell_levels[cell].first, cell_levels[cell].second);
643  for (unsigned int f=0; f<GeometryInfo<dim>::faces_per_cell; ++f)
644  {
645  // boundary face
646  if (face_is_owned[dcell->face(f)->index()] == FaceCategory::locally_active_at_boundary)
647  {
648  Assert(dcell->at_boundary(f), ExcInternalError());
649  ++boundary_counter;
650  FaceToCellTopology<1> info;
651  info.cells_interior[0] = cell;
652  info.cells_exterior[0] = numbers::invalid_unsigned_int;
653  info.interior_face_no = f;
654  info.exterior_face_no = dcell->face(f)->boundary_id();
655  info.subface_index = GeometryInfo<dim>::max_children_per_cell;
656  info.face_orientation = 0;
657  boundary_faces.push_back(info);
658 
659  face_visited[dcell->face(f)->index()]++;
660  }
661  // interior face, including faces over periodic boundaries
662  else
663  {
664  typename ::Triangulation<dim>::cell_iterator neighbor
665  = dcell->neighbor_or_periodic_neighbor(f);
666  if (use_active_cells && neighbor->has_children())
667  {
668  for (unsigned int c=0; c<dcell->face(f)->n_children(); ++c)
669  {
670  typename ::Triangulation<dim>::cell_iterator
671  neighbor_c = dcell->at_boundary(f) ?
672  dcell->periodic_neighbor_child_on_subface(f, c) :
673  dcell->neighbor_child_on_subface(f, c);
674  const types::subdomain_id neigh_domain = neighbor_c->subdomain_id();
675  const unsigned int neighbor_face_no =
676  dcell->has_periodic_neighbor(f) ?
677  dcell->periodic_neighbor_face_no(f) :
678  dcell->neighbor_face_no(f);
679  if (neigh_domain != dcell->subdomain_id() ||
680  face_visited[dcell->face(f)->child(c)->index()] == 1)
681  {
682  std::pair<unsigned int,unsigned int>
683  level_index(neighbor_c->level(), neighbor_c->index());
684  if (face_is_owned[dcell->face(f)->child(c)->index()]==
685  FaceCategory::locally_active_done_here)
686  {
687  ++inner_counter;
688  inner_faces.
689  push_back(create_face(neighbor_face_no, neighbor_c,
690  map_to_vectorized[level_index],
691  dcell, cell));
692 
693  }
694  else if (face_is_owned[dcell->face(f)->child(c)->index()] ==
695  FaceCategory::ghosted)
696  {
697  inner_ghost_faces.
698  push_back(create_face(neighbor_face_no, neighbor_c,
699  map_to_vectorized[level_index],
700  dcell, cell));
701  }
702  else
703  Assert(face_is_owned[dcell->face(f)->index()] ==
704  FaceCategory::locally_active_done_elsewhere,
705  ExcInternalError());
706  }
707  else
708  {
709  face_visited[dcell->face(f)->child(c)->index()] = 1;
710  }
711  }
712  }
713  else
714  {
715  const types::subdomain_id my_domain = use_active_cells ?
716  dcell->subdomain_id() : dcell->level_subdomain_id();
717  const types::subdomain_id neigh_domain = use_active_cells ?
718  neighbor->subdomain_id() : neighbor->level_subdomain_id();
719  if (neigh_domain != my_domain ||
720  face_visited[dcell->face(f)->index()] == 1)
721  {
722  std::pair<unsigned int,unsigned int>
723  level_index(neighbor->level(), neighbor->index());
724  if (face_is_owned[dcell->face(f)->index()]==
725  FaceCategory::locally_active_done_here)
726  {
727  ++inner_counter;
728  inner_faces.
729  push_back(create_face(f, dcell, cell, neighbor,
730  map_to_vectorized[level_index]));
731  }
732  else if (face_is_owned[dcell->face(f)->index()] ==
733  FaceCategory::ghosted)
734  {
735  inner_ghost_faces.
736  push_back(create_face(f, dcell, cell, neighbor,
737  map_to_vectorized[level_index]));
738  }
739  }
740  else
741  {
742  face_visited[dcell->face(f)->index()] = 1;
743  if (dcell->has_periodic_neighbor(f))
744  face_visited[neighbor->face(dcell->periodic_neighbor_face_no(f))->index()] = 1;
745  }
746  if (face_is_owned[dcell->face(f)->index()] ==
747  FaceCategory::multigrid_refinement_edge)
748  {
749  refinement_edge_faces.
750  push_back(create_face(f, dcell, cell, neighbor,
751  refinement_edge_faces.size()));
752  }
753  }
754  }
755  }
756  }
757  task_info.face_partition_data[partition+1]=
758  task_info.face_partition_data[partition] + inner_counter;
759  task_info.boundary_partition_data[partition+1] =
760  task_info.boundary_partition_data[partition] + boundary_counter;
761  }
762  task_info.ghost_face_partition_data.resize(2);
763  task_info.ghost_face_partition_data[0] = 0;
764  task_info.ghost_face_partition_data[1] = inner_ghost_faces.size();
765  task_info.refinement_edge_face_partition_data.resize(2);
766  task_info.refinement_edge_face_partition_data[0] = 0;
767  task_info.refinement_edge_face_partition_data[1] = refinement_edge_faces.size();
768  }
769 
770 
771 
772  template <int dim>
773  FaceToCellTopology<1>
775  ::create_face(const unsigned int face_no,
776  const typename ::Triangulation<dim>::cell_iterator &cell,
777  const unsigned int number_cell_interior,
778  const typename ::Triangulation<dim>::cell_iterator &neighbor,
779  const unsigned int number_cell_exterior)
780  {
781  FaceToCellTopology<1> info;
782  info.cells_interior[0] = number_cell_interior;
783  info.cells_exterior[0] = number_cell_exterior;
784  info.interior_face_no = face_no;
785  if (cell->has_periodic_neighbor(face_no))
786  info.exterior_face_no = cell->periodic_neighbor_face_no(face_no);
787  else
788  info.exterior_face_no = cell->neighbor_face_no(face_no);
789 
790  info.subface_index = GeometryInfo<dim>::max_children_per_cell;
791  Assert(neighbor->level() <= cell->level(),
792  ExcInternalError());
793  if (cell->level() > neighbor->level())
794  {
795  if (cell->has_periodic_neighbor(face_no))
796  info.subface_index =
797  cell->periodic_neighbor_of_coarser_periodic_neighbor(face_no).second;
798  else
799  info.subface_index =
800  cell->neighbor_of_coarser_neighbor(face_no).second;
801  }
802 
803  info.face_orientation = 0;
804  const unsigned int left_face_orientation =
805  !cell->face_orientation(face_no) + 2 * cell->face_flip(face_no) +
806  4 * cell->face_rotation(face_no);
807  const unsigned int right_face_orientation =
808  !neighbor->face_orientation(info.exterior_face_no) +
809  2 * neighbor->face_flip(info.exterior_face_no) +
810  4 * neighbor->face_rotation(info.exterior_face_no);
811  if (left_face_orientation != 0)
812  {
813  info.face_orientation = 8 + left_face_orientation;
814  Assert(right_face_orientation == 0,
815  ExcMessage("Face seems to be wrongly oriented from both sides"));
816  }
817  else
818  info.face_orientation = right_face_orientation;
819  return info;
820  }
821 
822 
823 
830  bool compare_faces_for_vectorization
831  (const FaceToCellTopology<1> &face1,
832  const FaceToCellTopology<1> &face2)
833  {
834  if (face1.interior_face_no != face2.interior_face_no)
835  return false;
836  if (face1.exterior_face_no != face2.exterior_face_no)
837  return false;
838  if (face1.subface_index != face2.subface_index)
839  return false;
840  if (face1.face_orientation != face2.face_orientation)
841  return false;
842  return true;
843  }
844 
845 
846 
853  template <int length>
854  struct FaceComparator
855  {
856  bool operator() (const FaceToCellTopology<length> &face1,
857  const FaceToCellTopology<length> &face2) const
858  {
859  for (unsigned int i=0; i<length; ++i)
860  if (face1.cells_interior[i] < face2.cells_interior[i])
861  return true;
862  else if (face1.cells_interior[i] > face2.cells_interior[i])
863  return false;
864  for (unsigned int i=0; i<length; ++i)
865  if (face1.cells_exterior[i] < face2.cells_exterior[i])
866  return true;
867  else if (face1.cells_exterior[i] > face2.cells_exterior[i])
868  return false;
869  if (face1.interior_face_no < face2.interior_face_no)
870  return true;
871  else if (face1.interior_face_no > face2.interior_face_no)
872  return false;
873  if (face1.exterior_face_no < face2.exterior_face_no)
874  return true;
875  else if (face1.exterior_face_no > face2.exterior_face_no)
876  return false;
877 
878  // we do not need to check for subface_index and orientation because
879  // those cannot be different if when all the other values are the
880  // same.
881  AssertDimension(face1.subface_index, face2.subface_index);
882  AssertDimension(face1.face_orientation, face2.face_orientation);
883 
884  return false;
885  }
886  };
887 
888 
889 
890  template <int vectorization_width>
891  void
892  collect_faces_vectorization
893  (const std::vector<FaceToCellTopology<1> > &faces_in,
894  const std::vector<bool> &hard_vectorization_boundary,
895  std::vector<unsigned int> &face_partition_data,
896  std::vector<FaceToCellTopology<vectorization_width> > &faces_out)
897  {
898  FaceToCellTopology<vectorization_width> macro_face;
899  std::vector<std::vector<unsigned int> > faces_type;
900 
901  unsigned int face_start = face_partition_data[0],
902  face_end = face_partition_data[0];
903 
904  face_partition_data[0] = faces_out.size();
905  for ( unsigned int partition=0; partition<face_partition_data.size()-1; ++partition)
906  {
907  std::vector<std::vector<unsigned int> > new_faces_type;
908 
909  // start with the end point for the last partition
910  face_start = face_end;
911  face_end = face_partition_data[partition+1];
912 
913  // set the partitioner to the new vectorized lengths
914  face_partition_data[partition+1] = face_partition_data[partition];
915 
916  // loop over the faces in the current partition and reorder according to
917  // the face type
918  for (unsigned int face=face_start; face<face_end; ++face)
919  {
920  for (unsigned int type=0; type<faces_type.size(); ++type)
921  {
922  // Compare current face with first face of type type
923  if ( compare_faces_for_vectorization(faces_in[face],
924  faces_in[faces_type[type][0]]) )
925  {
926  faces_type[type].push_back(face);
927  goto face_found;
928  }
929  }
930  faces_type.emplace_back(1, face);
931 face_found :
932  {}
933  }
934 
935  // insert new faces in sorted list to get good data locality
936  std::set<FaceToCellTopology<vectorization_width>,
937  FaceComparator<vectorization_width> > new_faces;
938  for (unsigned int type=0; type<faces_type.size(); ++type)
939  {
940  macro_face.interior_face_no = faces_in[faces_type[type][0]].interior_face_no;
941  macro_face.exterior_face_no = faces_in[faces_type[type][0]].exterior_face_no;
942  macro_face.subface_index = faces_in[faces_type[type][0]].subface_index;
943  macro_face.face_orientation = faces_in[faces_type[type][0]].face_orientation;
944  unsigned int no_faces = faces_type[type].size();
945  std::vector<unsigned char> touched(no_faces, 0);
946 
947  // do two passes through the data. The first is to identify similar
948  // faces within the same index range as the cells which will allow
949  // for vectorized read operations, the second picks up all the rest
950  unsigned int n_vectorized = 0;
951  for (unsigned int f=0; f<no_faces; ++f)
952  if (faces_in[faces_type[type][f]].cells_interior[0] % vectorization_width == 0)
953  {
954  bool is_contiguous = true;
955  if (f + vectorization_width > no_faces)
956  is_contiguous = false;
957  else
958  for (unsigned int v=1; v<vectorization_width; ++v)
959  if (faces_in[faces_type[type][f+v]].cells_interior[0] !=
960  faces_in[faces_type[type][f]].cells_interior[0]+v)
961  is_contiguous = false;
962  if (is_contiguous)
963  {
964  AssertIndexRange(f, faces_type[type].size()-vectorization_width+1);
965  for (unsigned int v=0; v<vectorization_width; ++v)
966  {
967  macro_face.cells_interior[v] = faces_in[faces_type[type][f+v]].cells_interior[0];
968  macro_face.cells_exterior[v] = faces_in[faces_type[type][f+v]].cells_exterior[0];
969  touched[f+v] = 1;
970  }
971  new_faces.insert(macro_face);
972  f += vectorization_width-1;
973  n_vectorized += vectorization_width;
974  }
975  }
976 
977  std::vector<unsigned int> untouched;
978  untouched.reserve(no_faces - n_vectorized);
979  for (unsigned int f=0; f<no_faces; ++f)
980  if (touched[f] == 0)
981  untouched.push_back(f);
982  unsigned int v=0;
983  for (auto f : untouched)
984  {
985  macro_face.cells_interior[v] = faces_in[faces_type[type][f]].cells_interior[0];
986  macro_face.cells_exterior[v] = faces_in[faces_type[type][f]].cells_exterior[0];
987  ++v;
988  if (v == vectorization_width)
989  {
990  new_faces.insert(macro_face);
991  v = 0;
992  }
993  }
994  if (v > 0 && v < vectorization_width)
995  {
996  // must add non-filled face
997  if (hard_vectorization_boundary[partition+1] ||
998  partition == face_partition_data.size()-2)
999  {
1000  for ( ; v < vectorization_width; ++v)
1001  {
1002  // Dummy cell, not used
1003  macro_face.cells_interior[v] = numbers::invalid_unsigned_int;
1004  macro_face.cells_exterior[v] = numbers::invalid_unsigned_int;
1005  }
1006  new_faces.insert(macro_face);
1007  }
1008  else
1009  {
1010  // postpone to the next partition
1011  std::vector<unsigned int> untreated(v);
1012  for (unsigned int f=0; f<v; ++f)
1013  untreated[f] = faces_type[type][*(untouched.end()-1-f)];
1014  new_faces_type.push_back(untreated);
1015  }
1016  }
1017  }
1018 
1019  // insert sorted list to vector of faces
1020  for (auto it = new_faces.begin(); it != new_faces.end(); ++it)
1021  faces_out.push_back(*it);
1022  face_partition_data[partition+1] += new_faces.size();
1023 
1024  // set the faces that were left over to faces_type for the next round
1025  faces_type = std::move(new_faces_type);
1026  }
1027 
1028 #ifdef DEBUG
1029  // final safety checks
1030  for (unsigned int i=0; i<faces_type.size(); ++i)
1031  AssertDimension(faces_type[i].size(), 0U);
1032 
1033  AssertDimension(faces_out.size(), face_partition_data.back());
1034  unsigned int nfaces = 0;
1035  for (unsigned int i=face_partition_data[0]; i<face_partition_data.back(); ++i)
1036  for (unsigned int v=0; v<vectorization_width; ++v)
1037  nfaces += (faces_out[i].cells_interior[v] != numbers::invalid_unsigned_int);
1038  AssertDimension(nfaces, faces_in.size());
1039 
1040  std::vector<std::pair<unsigned int,unsigned int>> in_faces, out_faces;
1041  for (unsigned int i=0; i<faces_in.size(); ++i)
1042  in_faces.emplace_back(faces_in[i].cells_interior[0],
1043  faces_in[i].cells_exterior[0]);
1044  for (unsigned int i=face_partition_data[0]; i<face_partition_data.back(); ++i)
1045  for (unsigned int v=0; v<vectorization_width &&
1046  faces_out[i].cells_interior[v] != numbers::invalid_unsigned_int; ++v)
1047  out_faces.emplace_back(faces_out[i].cells_interior[v],
1048  faces_out[i].cells_exterior[v]);
1049  std::sort(in_faces.begin(), in_faces.end());
1050  std::sort(out_faces.begin(), out_faces.end());
1051  AssertDimension(in_faces.size(), out_faces.size());
1052  for (unsigned int i=0; i<in_faces.size(); ++i)
1053  {
1054  AssertDimension(in_faces[i].first, out_faces[i].first);
1055  AssertDimension(in_faces[i].second, out_faces[i].second);
1056  }
1057 #endif
1058  }
1059 
1060 #endif // ifndef DOXYGEN
1061 
1062  }
1063 }
1064 
1065 
1066 DEAL_II_NAMESPACE_CLOSE
1067 
1068 #endif
static const unsigned int invalid_unsigned_int
Definition: types.h:173
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
#define AssertIndexRange(index, range)
Definition: exceptions.h:1284
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
unsigned int cells_interior[vectorization_width]
Definition: face_info.h:61
static ::ExceptionBase & ExcMessage(std::string arg1)
FaceToCellTopology< 1 > create_face(const unsigned int face_no, const typename ::Triangulation< dim >::cell_iterator &cell, const unsigned int number_cell_interior, const typename ::Triangulation< dim >::cell_iterator &neighbor, const unsigned int number_cell_exterior)
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices, const Partitioner partitioner=Partitioner::metis)
#define Assert(cond, exc)
Definition: exceptions.h:1142
void initialize(const ::Triangulation< dim > &triangulation, const MFAddData &additional_data, std::vector< std::pair< unsigned int, unsigned int > > &cell_levels)
void generate_faces(const ::Triangulation< dim > &triangulation, const std::vector< std::pair< unsigned int, unsigned int > > &cell_levels, TaskInfo &task_info)
unsigned int subdomain_id
Definition: types.h:42
Definition: cell_id.h:61
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcInternalError()