Reference documentation for deal.II version 9.0.0
task_info.cc
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 #include <deal.II/base/utilities.h>
18 #include <deal.II/base/memory_consumption.h>
19 #include <deal.II/base/parallel.h>
20 #include <deal.II/base/multithread_info.h>
21 #include <deal.II/base/mpi.h>
22 #include <deal.II/base/conditional_ostream.h>
23 
24 #include <deal.II/matrix_free/task_info.h>
25 
26 
27 #ifdef DEAL_II_WITH_THREADS
28 #include <tbb/task.h>
29 #include <tbb/task_scheduler_init.h>
30 #include <tbb/parallel_for.h>
31 #include <tbb/blocked_range.h>
32 #endif
33 
34 #include <iostream>
35 #include <set>
36 
37 DEAL_II_NAMESPACE_OPEN
38 
39 
40 
41 /*-------------------- Implementation of the matrix-free loop --------------*/
42 namespace internal
43 {
44  namespace MatrixFreeFunctions
45  {
46 #ifdef DEAL_II_WITH_THREADS
47 
48  // This defines the TBB data structures that are needed to schedule the
49  // partition-partition variant
50 
51  namespace partition
52  {
53  class ActualCellWork
54  {
55  public:
56  ActualCellWork (MFWorkerInterface **worker_pointer,
57  const unsigned int partition,
58  const TaskInfo &task_info)
59  :
60  worker(nullptr),
61  worker_pointer(worker_pointer),
63  task_info (task_info)
64  {}
65 
66  ActualCellWork (MFWorkerInterface &worker,
67  const unsigned int partition,
68  const TaskInfo &task_info)
69  :
70  worker (&worker),
71  worker_pointer (nullptr),
73  task_info (task_info)
74  {}
75 
76  void operator() () const
77  {
78  MFWorkerInterface *used_worker = worker != nullptr ? worker : *worker_pointer;
79  Assert(used_worker != nullptr, ExcInternalError());
80  used_worker->cell(std::make_pair(task_info.cell_partition_data[partition],
81  task_info.cell_partition_data[partition+1]));
82 
83  if (task_info.face_partition_data.empty() == false)
84  {
85  used_worker->face(std::make_pair(task_info.face_partition_data[partition],
86  task_info.face_partition_data[partition+1]));
87 
88  used_worker->boundary(std::make_pair(task_info.boundary_partition_data[partition],
89  task_info.boundary_partition_data[partition+1]));
90  }
91  }
92 
93  private:
94  MFWorkerInterface *worker;
95  MFWorkerInterface **worker_pointer;
96  const unsigned int partition;
97  const TaskInfo &task_info;
98  };
99 
100  class CellWork : public tbb::task
101  {
102  public:
103  CellWork (MFWorkerInterface &worker,
104  const unsigned int partition,
105  const TaskInfo &task_info,
106  const bool is_blocked)
107  :
108  dummy (nullptr),
109  work (worker, partition, task_info),
110  is_blocked (is_blocked)
111  {}
112 
113  tbb::task *execute ()
114  {
115  work();
116 
117  if (is_blocked==true)
118  dummy->spawn (*dummy);
119  return nullptr;
120  }
121 
122  tbb::empty_task *dummy;
123 
124  private:
125  ActualCellWork work;
126  const bool is_blocked;
127  };
128 
129 
130 
131  class PartitionWork : public tbb::task
132  {
133  public:
134  PartitionWork (MFWorkerInterface &function_in,
135  const unsigned int partition_in,
136  const TaskInfo &task_info_in,
137  const bool is_blocked_in = false)
138  :
139  dummy (nullptr),
140  function (function_in),
141  partition (partition_in),
142  task_info (task_info_in),
143  is_blocked (is_blocked_in)
144  {}
145 
146  tbb::task *execute ()
147  {
148  tbb::empty_task *root = new( tbb::task::allocate_root() )tbb::empty_task;
149  const unsigned int evens = task_info.partition_evens[partition];
150  const unsigned int odds = task_info.partition_odds[partition];
151  const unsigned int n_blocked_workers =
152  task_info.partition_n_blocked_workers[partition];
153  const unsigned int n_workers = task_info.partition_n_workers[partition];
154  std::vector<CellWork *> worker(n_workers);
155  std::vector<CellWork *> blocked_worker(n_blocked_workers);
156 
157  root->set_ref_count(evens+1);
158  for (unsigned int j=0; j<evens; j++)
159  {
160  worker[j] = new(root->allocate_child())
161  CellWork(function, task_info.
162  partition_row_index[partition]+2*j,
163  task_info, false);
164  if (j>0)
165  {
166  worker[j]->set_ref_count(2);
167  blocked_worker[j-1]->dummy = new(worker[j]->allocate_child())
168  tbb::empty_task;
169  worker[j-1]->spawn(*blocked_worker[j-1]);
170  }
171  else
172  worker[j]->set_ref_count(1);
173  if (j<evens-1)
174  {
175  blocked_worker[j] = new(worker[j]->allocate_child())
176  CellWork(function, task_info.
177  partition_row_index
178  [partition] + 2*j+1, task_info, true);
179  }
180  else
181  {
182  if (odds==evens)
183  {
184  worker[evens] = new(worker[j]->allocate_child())
185  CellWork(function, task_info.
186  partition_row_index[partition]+2*j+1,
187  task_info, false);
188  worker[j]->spawn(*worker[evens]);
189  }
190  else
191  {
192  tbb::empty_task *child = new(worker[j]->allocate_child())
193  tbb::empty_task();
194  worker[j]->spawn(*child);
195  }
196  }
197  }
198 
199  root->wait_for_all();
200  root->destroy(*root);
201  if (is_blocked==true)
202  dummy->spawn (*dummy);
203  return nullptr;
204  }
205 
206  tbb::empty_task *dummy;
207 
208  private:
209  MFWorkerInterface &function;
210  const unsigned int partition;
211  const TaskInfo &task_info;
212  const bool is_blocked;
213  };
214 
215  } // end of namespace partition
216 
217 
218 
219  namespace color
220  {
221  class CellWork
222  {
223  public:
224  CellWork (MFWorkerInterface &worker_in,
225  const TaskInfo &task_info_in,
226  const unsigned int partition_in)
227  :
228  worker (worker_in),
229  task_info (task_info_in),
230  partition (partition_in)
231  {}
232 
233  void operator()(const tbb::blocked_range<unsigned int> &r) const
234  {
235  const unsigned int start_index = task_info.cell_partition_data[partition]
236  + task_info.block_size * r.begin();
237  const unsigned int end_index = std::min(start_index +
238  task_info.block_size*(r.end()-r.begin()),
239  task_info.cell_partition_data[partition+1]);
240  worker.cell(std::make_pair(start_index, end_index));
241 
242  if (task_info.face_partition_data.empty() == false)
243  {
244  AssertThrow(false, ExcNotImplemented());
245  }
246  }
247  private:
248  MFWorkerInterface &worker;
249  const TaskInfo &task_info;
250  const unsigned int partition;
251  };
252 
253 
254 
255  class PartitionWork : public tbb::task
256  {
257  public:
258  PartitionWork (MFWorkerInterface &worker_in,
259  const unsigned int partition_in,
260  const TaskInfo &task_info_in,
261  const bool is_blocked_in)
262  :
263  dummy (nullptr),
264  worker (worker_in),
265  partition (partition_in),
266  task_info (task_info_in),
267  is_blocked (is_blocked_in)
268  {}
269 
270  tbb::task *execute ()
271  {
272  const unsigned int n_chunks = (task_info.cell_partition_data[partition+1]-
273  task_info.cell_partition_data[partition]+
274  task_info.block_size-1)/task_info.block_size;
275  parallel_for(tbb::blocked_range<unsigned int>(0,n_chunks,1),
276  CellWork (worker,task_info,partition));
277  if (is_blocked==true)
278  dummy->spawn (*dummy);
279  return nullptr;
280  }
281 
282  tbb::empty_task *dummy;
283 
284  private:
285  MFWorkerInterface &worker;
286  const unsigned int partition;
287  const TaskInfo &task_info;
288  const bool is_blocked;
289  };
290 
291  } // end of namespace color
292 
293 
294 
295  class MPICommunication : public tbb::task
296  {
297  public:
298  MPICommunication (MFWorkerInterface &worker_in,
299  const bool do_compress)
300  :
301  worker(worker_in),
302  do_compress(do_compress)
303  {}
304 
305  tbb::task *execute ()
306  {
307  if (do_compress == false)
308  worker.vector_update_ghosts_finish();
309  else
310  worker.vector_compress_start();
311  return nullptr;
312  }
313 
314  private:
315  MFWorkerInterface &worker;
316  const bool do_compress;
317  };
318 
319 #endif // DEAL_II_WITH_THREADS
320 
321 
322 
323  void
325  {
327 
328 #ifdef DEAL_II_WITH_THREADS
329 
330  if (scheme != none)
331  {
333  if (scheme == partition_partition)
334  {
335  tbb::empty_task *root = new( tbb::task::allocate_root() )
336  tbb::empty_task;
337  root->set_ref_count(evens+1);
338  std::vector<partition::PartitionWork *> worker(n_workers);
339  std::vector<partition::PartitionWork *>
340  blocked_worker(n_blocked_workers);
341  MPICommunication *worker_compr =
342  new(root->allocate_child())MPICommunication(funct, true);
343  worker_compr->set_ref_count(1);
344  for (unsigned int j=0; j<evens; j++)
345  {
346  if (j>0)
347  {
348  worker[j] = new(root->allocate_child())
349  partition::PartitionWork (funct,2*j,*this,false);
350  worker[j]->set_ref_count(2);
351  blocked_worker[j-1]->dummy = new(worker[j]->allocate_child())
352  tbb::empty_task;
353  if (j>1)
354  worker[j-1]->spawn(*blocked_worker[j-1]);
355  else
356  worker_compr->spawn(*blocked_worker[j-1]);
357  }
358  else
359  {
360  worker[j] = new(worker_compr->allocate_child())
361  partition::PartitionWork (funct,2*j,*this,false);
362  worker[j]->set_ref_count(2);
363  MPICommunication *worker_dist =
364  new (worker[j]->allocate_child())MPICommunication(funct, false);
365  worker_dist->spawn(*worker_dist);
366  }
367  if (j<evens-1)
368  {
369  blocked_worker[j] = new(worker[j]->allocate_child())
370  partition::PartitionWork(funct,2*j+1,*this,true);
371  }
372  else
373  {
374  if (odds==evens)
375  {
376  worker[evens] = new(worker[j]->allocate_child())
377  partition::PartitionWork(funct,2*j+1,*this,false);
378  worker[j]->spawn(*worker[evens]);
379  }
380  else
381  {
382  tbb::empty_task *child = new(worker[j]->allocate_child())
383  tbb::empty_task();
384  worker[j]->spawn(*child);
385  }
386  }
387  }
388 
389  root->wait_for_all();
390  root->destroy(*root);
391  }
392  else // end of partition-partition, start of partition-color
393  {
394  // check whether there is only one partition. if not, build up the
395  // tree of partitions
396  if (odds > 0)
397  {
398  tbb::empty_task *root = new( tbb::task::allocate_root() ) tbb::empty_task;
399  root->set_ref_count(evens+1);
400  const unsigned int n_blocked_workers = odds-(odds+evens+1)%2;
401  const unsigned int n_workers = cell_partition_data.size()-1-
403  std::vector<color::PartitionWork *> worker(n_workers);
404  std::vector<color::PartitionWork *> blocked_worker(n_blocked_workers);
405  unsigned int worker_index = 0, slice_index = 0;
406  unsigned int spawn_index = 0;
407  int spawn_index_child = -2;
408  MPICommunication *worker_compr =
409  new (root->allocate_child())MPICommunication(funct, true);
410  worker_compr->set_ref_count(1);
411  for (unsigned int part=0; part<partition_row_index.size()-1; part++)
412  {
413  const unsigned int spawn_index_new = worker_index;
414  if (part == 0)
415  worker[worker_index] = new(worker_compr->allocate_child())
416  color::PartitionWork(funct,slice_index,*this,false);
417  else
418  worker[worker_index] = new(root->allocate_child())
419  color::PartitionWork(funct,slice_index,*this,false);
420  slice_index++;
421  for (; slice_index<partition_row_index[part+1]; slice_index++)
422  {
423  worker[worker_index]->set_ref_count(1);
424  worker_index++;
425  worker[worker_index] = new (worker[worker_index-1]->allocate_child())
426  color::PartitionWork(funct,slice_index,*this,false);
427  }
428  worker[worker_index]->set_ref_count(2);
429  if (part>0)
430  {
431  blocked_worker[(part-1)/2]->dummy =
432  new (worker[worker_index]->allocate_child()) tbb::empty_task;
433  worker_index++;
434  if (spawn_index_child == -1)
435  worker[spawn_index]->spawn(*blocked_worker[(part-1)/2]);
436  else
437  {
438  Assert(spawn_index_child>=0, ExcInternalError());
439  worker[spawn_index]->spawn(*worker[spawn_index_child]);
440  }
441  spawn_index = spawn_index_new;
442  spawn_index_child = -2;
443  }
444  else
445  {
446  MPICommunication *worker_dist =
447  new (worker[worker_index]->allocate_child())MPICommunication(funct,false);
448  worker_dist->spawn(*worker_dist);
449  worker_index++;
450  }
451  part += 1;
452  if (part<partition_row_index.size()-1)
453  {
454  if (part<partition_row_index.size()-2)
455  {
456  blocked_worker[part/2] = new(worker[worker_index-1]->allocate_child())
457  color::PartitionWork(funct,slice_index,*this,true);
458  slice_index++;
459  if (slice_index<partition_row_index[part+1])
460  {
461  blocked_worker[part/2]->set_ref_count(1);
462  worker[worker_index] = new(blocked_worker[part/2]->allocate_child())
463  color::PartitionWork(funct,slice_index,*this,false);
464  slice_index++;
465  }
466  else
467  {
468  spawn_index_child = -1;
469  continue;
470  }
471  }
472  for (; slice_index<partition_row_index[part+1];
473  slice_index++)
474  {
475  if (slice_index>partition_row_index[part])
476  {
477  worker[worker_index]->set_ref_count(1);
478  worker_index++;
479  }
480  worker[worker_index] = new (worker[worker_index-1]->allocate_child())
481  color::PartitionWork(funct,slice_index,*this,false);
482  }
483  spawn_index_child = worker_index;
484  worker_index++;
485  }
486  else
487  {
488  tbb::empty_task *final = new (worker[worker_index-1]->allocate_child())
489  tbb::empty_task;
490  worker[spawn_index]->spawn(*final);
491  spawn_index_child = worker_index-1;
492  }
493  }
494  if (evens==odds)
495  {
496  Assert(spawn_index_child>=0, ExcInternalError());
497  worker[spawn_index]->spawn(*worker[spawn_index_child]);
498  }
499  root->wait_for_all();
500  root->destroy(*root);
501  }
502  // case when we only have one partition: this is the usual coloring
503  // scheme, and we just schedule a parallel for loop for each color
504  else
505  {
508 
509  for (unsigned int color=0; color < partition_row_index[1]; ++color)
510  {
511  tbb::empty_task *root = new( tbb::task::allocate_root() ) tbb::empty_task;
512  root->set_ref_count(2);
513  color::PartitionWork *worker =
514  new (root->allocate_child())color::PartitionWork(funct,color,*this,false);
515  root->spawn(*worker);
516  root->wait_for_all();
517  root->destroy(*root);
518  }
519 
520  funct.vector_compress_start();
521  }
522  }
523  }
524  else
525 #endif
526  // serial loop, go through up to three times and do the MPI transfer at
527  // the beginning/end of the second part
528  {
529  for (unsigned int part = 0; part < partition_row_index.size()-2; ++part)
530  {
531  if (part == 1)
533 
534  for (unsigned int i=partition_row_index[part]; i<partition_row_index[part+1]; ++i)
535  {
538  {
539  funct.zero_dst_vector_range(i);
540  funct.cell(std::make_pair(cell_partition_data[i],
541  cell_partition_data[i+1]));
542  }
543 
544  if (face_partition_data.empty() == false)
545  {
547  funct.face(std::make_pair(face_partition_data[i],
548  face_partition_data[i+1]));
550  funct.boundary(std::make_pair(boundary_partition_data[i],
552  }
553  }
554 
555  if (part == 1)
556  funct.vector_compress_start();
557  }
558  }
559  funct.vector_compress_finish();
560  }
561 
562 
563 
565  {
566  clear();
567  }
568 
569 
570 
572  {
573  n_active_cells = 0;
574  n_ghost_cells = 0;
576  block_size = 0;
577  n_blocks = 0;
578  scheme = none;
579  partition_row_index.clear();
580  cell_partition_data.clear();
581  face_partition_data.clear();
582  boundary_partition_data.clear();
583  evens = 0;
584  odds = 0;
585  n_blocked_workers = 0;
586  n_workers = 0;
587  partition_evens.clear();
588  partition_odds.clear();
590  partition_n_workers.clear();
591  communicator = MPI_COMM_SELF;
592  my_pid = 0;
593  n_procs = 1;
594  }
595 
596 
597 
598  template <typename StreamType>
599  void TaskInfo::print_memory_statistics (StreamType &out,
600  const std::size_t data_length) const
601  {
603  = Utilities::MPI::min_max_avg (1e-6*data_length, communicator);
604  if (n_procs < 2)
605  out << memory_c.min;
606  else
607  out << memory_c.min << "/" << memory_c.avg << "/" << memory_c.max;
608  out << " MB" << std::endl;
609  }
610 
611 
612 
613  std::size_t
615  {
616  return (sizeof(*this)+
625  }
626 
627 
628 
629  void
630  TaskInfo::collect_boundary_cells (const unsigned int n_active_cells_in,
631  const unsigned int n_active_and_ghost_cells,
632  const unsigned int vectorization_length_in,
633  std::vector<unsigned int> &boundary_cells)
634  {
635  vectorization_length = vectorization_length_in;
636  n_active_cells = n_active_cells_in;
637  n_ghost_cells = n_active_and_ghost_cells - n_active_cells;
638 
639  // try to make the number of boundary cells divisible by the number of
640  // vectors in vectorization
641  unsigned int fillup_needed =
643  if (fillup_needed > 0 && boundary_cells.size() < n_active_cells)
644  {
645  // fill additional cells into the list of boundary cells to get a
646  // balanced number. Go through the indices successively until we
647  // found enough indices
648  std::vector<unsigned int> new_boundary_cells;
649  new_boundary_cells.reserve (boundary_cells.size());
650 
651  unsigned int next_free_slot = 0, bound_index = 0;
652  while (fillup_needed > 0 && bound_index < boundary_cells.size())
653  {
654  if (next_free_slot < boundary_cells[bound_index])
655  {
656  // check if there are enough cells to fill with in the
657  // current slot
658  if (next_free_slot + fillup_needed <= boundary_cells[bound_index])
659  {
660  for (unsigned int j=boundary_cells[bound_index]-fillup_needed;
661  j < boundary_cells[bound_index]; ++j)
662  new_boundary_cells.push_back(j);
663  fillup_needed = 0;
664  }
665  // ok, not enough indices, so just take them all up to the
666  // next boundary cell
667  else
668  {
669  for (unsigned int j=next_free_slot;
670  j<boundary_cells[bound_index]; ++j)
671  new_boundary_cells.push_back(j);
672  fillup_needed -= boundary_cells[bound_index]-next_free_slot;
673  }
674  }
675  new_boundary_cells.push_back(boundary_cells[bound_index]);
676  next_free_slot = boundary_cells[bound_index]+1;
677  ++bound_index;
678  }
679  while (fillup_needed > 0 && (new_boundary_cells.size()==0 ||
680  new_boundary_cells.back()<n_active_cells-1))
681  new_boundary_cells.push_back(new_boundary_cells.back()+1);
682  while (bound_index<boundary_cells.size())
683  new_boundary_cells.push_back(boundary_cells[bound_index++]);
684 
685  boundary_cells.swap(new_boundary_cells);
686  }
687 
688  // set the number of cells
689  std::sort (boundary_cells.begin(), boundary_cells.end());
690 
691  // check that number of boundary cells is divisible by
692  // vectorization_length or that it contains all cells
693  Assert (boundary_cells.size() % vectorization_length == 0 ||
694  boundary_cells.size() == n_active_cells, ExcInternalError());
695  }
696 
697 
698 
699  void
700  TaskInfo
701  ::create_blocks_serial (const std::vector<unsigned int> &boundary_cells,
702  const std::vector<unsigned int> &cells_close_to_boundary,
703  const unsigned int dofs_per_cell,
704  const std::vector<unsigned int> &cell_vectorization_categories,
705  const bool cell_vectorization_categories_strict,
706  std::vector<unsigned int> &renumbering,
707  std::vector<unsigned char> &incompletely_filled_vectorization)
708  {
709  const unsigned int n_macro_cells =
710  (n_active_cells + vectorization_length - 1) / vectorization_length;
711  const unsigned int n_ghost_slots =
712  (n_ghost_cells + vectorization_length - 1) / vectorization_length;
713  const unsigned int n_boundary_cells = boundary_cells.size();
714 
715  incompletely_filled_vectorization.resize (n_macro_cells+n_ghost_slots);
716  renumbering.resize(n_active_cells + n_ghost_cells,
718 
719  // Define the outer number of partitions. In the MPI case, we have three
720  // partitions (part before comm, part with comm, part after comm)
721  if (n_procs == 1)
722  partition_row_index.resize(3);
723  else
724  partition_row_index.resize(5);
725 
726  // Initially mark the cells according to the MPI ranking
727  std::vector<unsigned char> cell_marked(n_active_cells+n_ghost_cells, 0);
728  if (n_procs > 1)
729  {
730  for (unsigned int i=0; i<n_boundary_cells; ++i)
731  cell_marked[boundary_cells[i]] = 2;
732 
733  Assert(boundary_cells.size()%vectorization_length == 0 ||
734  boundary_cells.size() == n_active_cells,
735  ExcInternalError());
736 
737  const unsigned int n_second_slot =
738  ((n_active_cells - n_boundary_cells)/2/vectorization_length)*vectorization_length;
739  unsigned int count = 0;
740  for (unsigned int i=0; i<cells_close_to_boundary.size(); ++i)
741  if (cell_marked[cells_close_to_boundary[i]] == 0)
742  {
743  cell_marked[cells_close_to_boundary[i]] = count<n_second_slot ? 1 : 3;
744  ++count;
745  }
746 
747  unsigned int c=0;
748  for ( ; c<n_active_cells && count < n_second_slot; ++c)
749  if (cell_marked[c] == 0)
750  {
751  cell_marked[c] = 1;
752  ++count;
753  }
754  for ( ; c < n_active_cells; ++c)
755  if (cell_marked[c] == 0)
756  cell_marked[c] = 3;
757  for ( ; c < n_active_cells+n_ghost_cells; ++c)
758  if (cell_marked[c] == 0)
759  cell_marked[c] = 4;
760  }
761  else
762  std::fill(cell_marked.begin(), cell_marked.end(), 1);
763 
764  for (unsigned int i=0; i<cell_marked.size(); ++i)
765  Assert(cell_marked[i] != 0, ExcInternalError());
766 
767  unsigned int n_categories = 1;
768  std::vector<unsigned int> tight_category_map;
769  if (cell_vectorization_categories.empty() == false)
770  {
771  AssertDimension(cell_vectorization_categories.size(),
772  n_active_cells+n_ghost_cells);
773 
774  // create a tight map of categories for not taking exceeding amounts
775  // of memory below. Sort the new categories by the numbers in the
776  // old one.
777  tight_category_map.reserve(n_active_cells+n_ghost_cells);
778  std::set<unsigned int> used_categories;
779  for (unsigned int i=0; i<n_active_cells+n_ghost_cells; ++i)
780  used_categories.insert(cell_vectorization_categories[i]);
781  std::vector<unsigned int> used_categories_vector(used_categories.size());
782  n_categories = 0;
783  for (auto &it : used_categories)
784  used_categories_vector[n_categories++] = it;
785  for (unsigned int i=0; i<n_active_cells+n_ghost_cells; ++i)
786  {
787  const unsigned int index = std::lower_bound(used_categories_vector.begin(),
788  used_categories_vector.end(),
789  cell_vectorization_categories[i])
790  - used_categories_vector.begin();
791  AssertIndexRange(index, used_categories_vector.size());
792  tight_category_map[i] = index;
793  }
794 
795  // leave some more space for empty lanes
796  incompletely_filled_vectorization.resize(incompletely_filled_vectorization.size()
797  +4*n_categories);
798  }
799  else if (cells_close_to_boundary.empty())
800  tight_category_map.resize(n_active_cells+n_ghost_cells, 0);
801  else
802  {
803  n_categories = 2;
804  tight_category_map.resize(n_active_cells+n_ghost_cells, 1);
805  for (unsigned int i=0; i<cells_close_to_boundary.size(); ++i)
806  tight_category_map[cells_close_to_boundary[i]] = 0;
807  }
808 
809  cell_partition_data.clear();
810  cell_partition_data.resize(1, 0);
811  unsigned int counter = 0;
812  unsigned int n_cells = 0;
813  std::vector<std::vector<unsigned int> > renumbering_category(n_categories);
814  for (unsigned int block=1; block<(n_procs>1u ? 5u : 3u); ++block)
815  {
816  // step 1: sort by category
817  for (unsigned int i=0; i<n_active_cells+n_ghost_cells; ++i)
818  if (cell_marked[i] == block)
819  renumbering_category[tight_category_map[i]].push_back(i);
820 
821  // step 2: if we want to fill up the ranges in vectorization, promote
822  // some of the cells to a higher category
823  if (cell_vectorization_categories_strict == false && n_categories > 1)
824  for (unsigned int j=n_categories-1; j>0; --j)
825  {
826  unsigned int lower_index = j-1;
827  while (renumbering_category[j].size()%vectorization_length)
828  {
829  while (renumbering_category[j].size()%vectorization_length &&
830  !renumbering_category[lower_index].empty())
831  {
832  renumbering_category[j].push_back(renumbering_category[lower_index].back());
833  renumbering_category[lower_index].pop_back();
834  }
835  if (lower_index == 0)
836  break;
837  else
838  --lower_index;
839  }
840  }
841 
842  // step 3: append cells according to categories
843  for (unsigned int j=0; j<n_categories; ++j)
844  {
845  for (unsigned int jj=0; jj<renumbering_category[j].size(); jj++)
846  renumbering[counter++] = renumbering_category[j][jj];
847  unsigned int remainder = renumbering_category[j].size()%vectorization_length;
848  if (remainder)
849  incompletely_filled_vectorization
850  [renumbering_category[j].size()/vectorization_length+n_cells]
851  = remainder;
852  const unsigned int n_my_macro_cells =
853  (renumbering_category[j].size()+vectorization_length-1)/vectorization_length;
854  renumbering_category[j].clear();
855 
856  // step 4: create blocks for face integrals, make the number of
857  // cells divisible by 4 if possible
858  const unsigned int block_size = std::max((2048U/dofs_per_cell)/8*4, 2U);
859  if (block < 4)
860  for (unsigned int k=0; k<n_my_macro_cells; k+=block_size)
861  cell_partition_data.push_back(n_cells +
862  std::min(k+block_size,
863  n_my_macro_cells));
864  else
865  cell_partition_data.back() += n_my_macro_cells;
866  n_cells += n_my_macro_cells;
867  }
868  partition_row_index[block] = cell_partition_data.size()-1;
869  if (block == 3 || (block==1 && n_procs == 1))
870  cell_partition_data.push_back(n_cells);
871  }
872  if (cell_vectorization_categories_strict == true)
873  Assert(n_cells >= n_macro_cells+n_ghost_slots, ExcInternalError())
874  else
875  AssertDimension(n_cells, n_macro_cells+n_ghost_slots);
876  AssertDimension(cell_partition_data.back(), n_cells);
877  AssertDimension(counter, n_active_cells+n_ghost_cells);
878 
879  incompletely_filled_vectorization.resize(cell_partition_data.back());
880  }
881 
882 
883 
884  void
885  TaskInfo
886  ::initial_setup_blocks_tasks(const std::vector<unsigned int> &boundary_cells,
887  std::vector<unsigned int> &renumbering,
888  std::vector<unsigned char> &incompletely_filled_vectorization)
889  {
890  const unsigned int n_macro_cells =
891  (n_active_cells + vectorization_length - 1) / vectorization_length;
892  const unsigned int n_ghost_slots =
893  (n_ghost_cells + vectorization_length - 1) / vectorization_length;
894  incompletely_filled_vectorization.resize (n_macro_cells+n_ghost_slots);
895  if (n_macro_cells*vectorization_length > n_active_cells)
896  incompletely_filled_vectorization[n_macro_cells-1] =
897  vectorization_length - (n_macro_cells*vectorization_length - n_active_cells);
898  if (n_ghost_slots*vectorization_length > n_ghost_cells)
899  incompletely_filled_vectorization[n_macro_cells+n_ghost_slots-1] =
900  vectorization_length - (n_ghost_slots*vectorization_length - n_ghost_cells);
901 
902  std::vector<unsigned int> reverse_numbering (n_active_cells,
904  for (unsigned int j=0; j<boundary_cells.size(); ++j)
905  reverse_numbering[boundary_cells[j]] = j;
906  unsigned int counter = boundary_cells.size();
907  for (unsigned int j=0; j<n_active_cells; ++j)
908  if (reverse_numbering[j] == numbers::invalid_unsigned_int)
909  reverse_numbering[j] = counter++;
910 
911  AssertDimension (counter, n_active_cells);
912  renumbering = Utilities::invert_permutation (reverse_numbering);
913 
914  for (unsigned int j=n_active_cells; j<n_active_cells+n_ghost_cells; ++j)
915  renumbering.push_back(j);
916 
917  // TODO: might be able to simplify this code by not relying on the cell
918  // partition data while computing the thread graph
919  cell_partition_data.clear();
920  cell_partition_data.push_back(0);
921  if (n_procs > 1)
922  {
923  const unsigned int n_macro_boundary_cells =
924  (boundary_cells.size()+vectorization_length-1)/vectorization_length;
925  cell_partition_data.push_back((n_macro_cells-n_macro_boundary_cells)/2);
926  cell_partition_data.push_back(cell_partition_data[1] + n_macro_boundary_cells);
927  }
928  else
929  AssertDimension(boundary_cells.size(), 0);
930  cell_partition_data.push_back(n_macro_cells);
931  cell_partition_data.push_back(cell_partition_data.back() + n_ghost_slots);
932  partition_row_index.resize(n_procs > 1 ? 4 : 2);
933  partition_row_index[0] = 0;
934  partition_row_index[1] = 1;
935  if (n_procs > 1)
936  {
937  partition_row_index[2] = 2;
938  partition_row_index[3] = 3;
939  }
940  }
941 
942 
943 
944  void
945  TaskInfo::guess_block_size (const unsigned int dofs_per_cell)
946  {
947  // user did not say a positive number, so we have to guess
948  if (block_size == 0)
949  {
950  // we would like to have enough work to do, so as first guess, try
951  // to get 16 times as many chunks as we have threads on the system.
953  16 * vectorization_length);
954 
955  // if there are too few degrees of freedom per cell, need to
956  // increase the block size
957  const unsigned int minimum_parallel_grain_size = 200;
958  if (dofs_per_cell * block_size <
959  minimum_parallel_grain_size)
960  block_size = (minimum_parallel_grain_size /
961  dofs_per_cell + 1);
962  if (dofs_per_cell * block_size > 10000)
963  block_size /= 4;
964 
965  block_size = 1 << (unsigned int)(log2(block_size+1));
966  }
968  block_size = std::max(1U, n_active_cells);
969  }
970 
971 
972 
973  void
975  (DynamicSparsityPattern &connectivity_large,
976  std::vector<unsigned int> &renumbering,
977  std::vector<unsigned char> &irregular_cells,
978  const bool )
979  {
980  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
981  if (n_macro_cells == 0)
982  return;
983 
984  Assert (vectorization_length > 0, ExcInternalError());
985 
986  unsigned int partition = 0, counter = 0;
987 
988  // Create connectivity graph for blocks based on connectivity graph for cells.
989  DynamicSparsityPattern connectivity(n_blocks,
990  n_blocks);
991  make_connectivity_cells_to_blocks(irregular_cells, connectivity_large, connectivity);
992 
993  // Create cell-block partitioning.
994 
995  // For each block of cells, this variable saves to which partitions the
996  // block belongs. Initialize all to -1 to mark them as not yet assigned
997  // a partition.
998  std::vector<unsigned int> cell_partition(n_blocks,
1000 
1001  // In element j of this variable, one puts the old number of the block
1002  // that should be the jth block in the new numeration.
1003  std::vector<unsigned int> partition_list (n_blocks,0);
1004  std::vector<unsigned int> partition_color_list(n_blocks,0);
1005 
1006  // This vector points to the start of each partition.
1007  std::vector<unsigned int> partition_size (2,0);
1008 
1009  //blocking_connectivity = true;
1010 
1011  // The cluster_size in make_partitioning defines that the no. of cells
1012  // in each partition should be a multiple of cluster_size.
1013  unsigned int cluster_size = 1;
1014 
1015  // Make the partitioning of the first layer of the blocks of cells.
1016  make_partitioning( connectivity, cluster_size, cell_partition,
1017  partition_list, partition_size, partition );
1018 
1019  // Color the cells within each partition
1020  make_coloring_within_partitions_pre_blocked
1021  (connectivity, partition, cell_partition,
1022  partition_list, partition_size, partition_color_list);
1023 
1024  partition_list = renumbering;
1025 
1026 #ifdef DEBUG
1027  // in debug mode, check that the partition color list is one-to-one
1028  {
1029  std::vector<unsigned int> sorted_pc_list (partition_color_list);
1030  std::sort(sorted_pc_list.begin(), sorted_pc_list.end());
1031  for (unsigned int i=0; i<sorted_pc_list.size(); ++i)
1032  Assert(sorted_pc_list[i] == i, ExcInternalError());
1033  }
1034 #endif
1035 
1036  // set the start list for each block and compute the renumbering of
1037  // cells
1038  std::vector<unsigned int> block_start(n_macro_cells+1);
1039  std::vector<unsigned char> irregular(n_macro_cells);
1040 
1041  unsigned int mcell_start=0;
1042  block_start[0] = 0;
1043  for (unsigned int block=0; block<n_blocks; block++)
1044  {
1045  block_start[block+1] = block_start[block];
1046  for (unsigned int mcell=mcell_start; mcell<
1047  std::min(mcell_start+block_size, n_macro_cells);
1048  ++mcell)
1049  {
1050  unsigned int n_comp = (irregular_cells[mcell]>0)
1051  ?irregular_cells[mcell]:vectorization_length;
1052  block_start[block+1] += n_comp;
1053  ++counter;
1054  }
1055  mcell_start += block_size;
1056  }
1057  counter = 0;
1058  unsigned int counter_macro = 0;
1059  unsigned int block_size_last =
1060  n_macro_cells - block_size * (n_blocks-1);
1061  if (block_size_last == 0)
1062  block_size_last = block_size;
1063 
1064  unsigned int tick = 0;
1065  for (unsigned int block=0; block<n_blocks; block++)
1066  {
1067  unsigned int present_block = partition_color_list[block];
1068  for (unsigned int cell = block_start[present_block];
1069  cell<block_start[present_block+1]; ++cell)
1070  renumbering[counter++] = partition_list[cell];
1071  unsigned int this_block_size = (present_block == n_blocks-1)?
1072  block_size_last:block_size;
1073 
1074  // Also re-compute the content of cell_partition_data to
1075  // contain the numbers of cells, not blocks
1076  if (cell_partition_data[tick] == block)
1077  cell_partition_data[tick++] = counter_macro;
1078 
1079  for (unsigned int j=0; j<this_block_size; j++)
1080  irregular[counter_macro++] =
1081  irregular_cells[present_block*block_size+j];
1082  }
1083  AssertDimension(tick+1, cell_partition_data.size());
1084  cell_partition_data.back() = counter_macro;
1085 
1086  irregular_cells.swap(irregular);
1087  AssertDimension (counter, n_active_cells);
1088  AssertDimension (counter_macro, n_macro_cells);
1089 
1090  // check that the renumbering is one-to-one
1091 #ifdef DEBUG
1092  {
1093  std::vector<unsigned int> sorted_renumbering (renumbering);
1094  std::sort(sorted_renumbering.begin(), sorted_renumbering.end());
1095  for (unsigned int i=0; i<sorted_renumbering.size(); ++i)
1096  Assert(sorted_renumbering[i] == i, ExcInternalError());
1097  }
1098 #endif
1099 
1100 
1101  update_task_info(partition); // Actually sets too much for partition color case
1102 
1103  AssertDimension(cell_partition_data.back(), n_macro_cells);
1104  }
1105 
1106 
1107 
1108  void
1110  (const std::vector<unsigned int> &cell_active_fe_index,
1111  DynamicSparsityPattern &connectivity,
1112  std::vector<unsigned int> &renumbering,
1113  std::vector<unsigned char> &irregular_cells,
1114  const bool hp_bool)
1115  {
1116  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
1117  if (n_macro_cells == 0)
1118  return;
1119 
1120  Assert (vectorization_length > 0, ExcInternalError());
1121 
1122  // if we want to block before partitioning, create connectivity graph
1123  // for blocks based on connectivity graph for cells.
1124  DynamicSparsityPattern connectivity_blocks(n_blocks,
1125  n_blocks);
1126  make_connectivity_cells_to_blocks(irregular_cells, connectivity, connectivity_blocks);
1127 
1128  unsigned int n_blocks = 0;
1129  if ( scheme == partition_color || scheme == color )// blocking_connectivity == true
1130  n_blocks = this->n_blocks;
1131  else
1132  n_blocks = n_active_cells;
1133 
1134  // For each block of cells, this variable saves to which partitions the
1135  // block belongs. Initialize all to -1 to mark them as not yet assigned
1136  // a partition.
1137  std::vector<unsigned int> cell_partition(n_blocks,
1139 
1140  // In element j of this variable, one puts the old number (but after
1141  // renumbering according to the input renumbering) of the block that
1142  // should be the jth block in the new numeration.
1143  std::vector<unsigned int> partition_list (n_blocks,0);
1144  std::vector<unsigned int> partition_2layers_list(n_blocks,0);
1145 
1146  // This vector points to the start of each partition.
1147  std::vector<unsigned int> partition_size (2,0);
1148 
1149  unsigned int partition = 0;
1150 
1151  // Within the partitions we want to be able to block for the case that
1152  // we do not block already in the connectivity. The cluster_size in
1153  // make_partitioning defines that the no. of cells in each partition
1154  // should be a multiple of cluster_size.
1155  unsigned int cluster_size = 1;
1156  if (scheme == partition_partition)
1157  cluster_size = block_size*vectorization_length;
1158 
1159  // Make the partitioning of the first layer of the blocks of cells.
1160  if ( scheme == partition_color || scheme == color )
1161  make_partitioning( connectivity_blocks, cluster_size, cell_partition,
1162  partition_list, partition_size, partition);
1163  else
1164  make_partitioning( connectivity, cluster_size, cell_partition,
1165  partition_list, partition_size, partition);
1166 
1167  // Partition or color second layer
1168  if ( scheme == partition_partition )
1169 
1170  {
1171  // Partition within partitions.
1172  make_partitioning_within_partitions_post_blocked
1173  (connectivity, cell_active_fe_index, partition, cluster_size, hp_bool,
1174  cell_partition, partition_list, partition_size,
1175  partition_2layers_list, irregular_cells);
1176  }
1177  else if ( scheme == partition_color || scheme == color )
1178  {
1179  make_coloring_within_partitions_pre_blocked
1180  (connectivity_blocks, partition, cell_partition,
1181  partition_list, partition_size, partition_2layers_list);
1182  }
1183 
1184  // in debug mode, check that the partition_2layers_list is one-to-one
1185 #ifdef DEBUG
1186  {
1187  std::vector<unsigned int> sorted_pc_list (partition_2layers_list);
1188  std::sort(sorted_pc_list.begin(), sorted_pc_list.end());
1189  for (unsigned int i=0; i<sorted_pc_list.size(); ++i)
1190  Assert(sorted_pc_list[i] == i, ExcInternalError());
1191  }
1192 #endif
1193 
1194  // Set the new renumbering
1195  std::vector<unsigned int> renumbering_in (n_active_cells,0);
1196  renumbering_in.swap(renumbering);
1197  if (scheme == partition_partition) // blocking_connectivity == false
1198  {
1199  // This is the simple case. The renumbering is just a combination of
1200  // the renumbering that we were given as an input and the
1201  // renumbering of partition/coloring given in partition_2layers_list
1202  for (unsigned int j=0; j<renumbering.size(); j++)
1203  renumbering[j] = renumbering_in[partition_2layers_list[j]];
1204  // Account for the ghost cells, finally.
1205  for (unsigned int i=0; i<n_ghost_cells; ++i)
1206  renumbering.push_back(i+n_active_cells);
1207  }
1208  else
1209  {
1210  // set the start list for each block and compute the renumbering of
1211  // cells
1212  std::vector<unsigned int> block_start(n_macro_cells+1);
1213  std::vector<unsigned char> irregular(n_macro_cells);
1214 
1215  unsigned int counter = 0;
1216  unsigned int mcell_start=0;
1217  block_start[0] = 0;
1218  for (unsigned int block=0; block<n_blocks; block++)
1219  {
1220  block_start[block+1] = block_start[block];
1221  for (unsigned int mcell=mcell_start; mcell<
1222  std::min(mcell_start+block_size, n_macro_cells);
1223  ++mcell)
1224  {
1225  unsigned int n_comp = (irregular_cells[mcell]>0)
1226  ?irregular_cells[mcell]:vectorization_length;
1227  block_start[block+1] += n_comp;
1228  ++counter;
1229  }
1230  mcell_start += block_size;
1231  }
1232  counter = 0;
1233  unsigned int counter_macro = 0;
1234  unsigned int block_size_last =
1235  n_macro_cells - block_size * (n_blocks-1);
1236  if (block_size_last == 0)
1237  block_size_last = block_size;
1238 
1239  unsigned int tick = 0;
1240  for (unsigned int block=0; block<n_blocks; block++)
1241  {
1242  unsigned int present_block = partition_2layers_list[block];
1243  for (unsigned int cell = block_start[present_block];
1244  cell<block_start[present_block+1]; ++cell)
1245  renumbering[counter++] = renumbering_in[cell];
1246  unsigned int this_block_size = (present_block == n_blocks-1)?
1247  block_size_last:block_size;
1248 
1249  // Also re-compute the content of cell_partition_data to
1250  // contain the numbers of cells, not blocks
1251  if (cell_partition_data[tick] == block)
1252  cell_partition_data[tick++] = counter_macro;
1253 
1254  for (unsigned int j=0; j<this_block_size; j++)
1255  irregular[counter_macro++] =
1256  irregular_cells[present_block*block_size+j];
1257  }
1258  AssertDimension(tick+1, cell_partition_data.size());
1259  cell_partition_data.back() = counter_macro;
1260 
1261  irregular_cells.swap(irregular);
1262  AssertDimension (counter, n_active_cells);
1263  AssertDimension (counter_macro, n_macro_cells);
1264  // check that the renumbering is one-to-one
1265 #ifdef DEBUG
1266  {
1267  std::vector<unsigned int> sorted_renumbering (renumbering);
1268  std::sort(sorted_renumbering.begin(), sorted_renumbering.end());
1269  for (unsigned int i=0; i<sorted_renumbering.size(); ++i)
1270  Assert(sorted_renumbering[i] == i, ExcInternalError());
1271  }
1272 #endif
1273  }
1274 
1275  // Update the task_info with the more information for the thread graph.
1276  update_task_info(partition);
1277 
1278  }
1279 
1280 
1281 
1282  void
1284  (const std::vector<unsigned int> &cell_active_fe_index,
1285  DynamicSparsityPattern &connectivity,
1286  std::vector<unsigned int> &renumbering,
1287  std::vector<unsigned char> &irregular_cells,
1288  const bool hp_bool)
1289  {
1290  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
1291  if (n_macro_cells == 0)
1292  return;
1293 
1294  const unsigned int cluster_size = block_size*vectorization_length;
1295 
1296  // Create cell-block partitioning.
1297 
1298  // For each block of cells, this variable saves to which partitions the
1299  // block belongs. Initialize all to n_macro_cells to mark them as not
1300  // yet assigned a partition.
1301  std::vector<unsigned int> cell_partition (n_active_cells,
1303 
1304 
1305  // In element j of this variable, one puts the old number of the block
1306  // that should be the jth block in the new numeration.
1307  std::vector<unsigned int> partition_list(n_active_cells,0);
1308  std::vector<unsigned int> partition_partition_list(n_active_cells,0);
1309 
1310  // This vector points to the start of each partition.
1311  std::vector<unsigned int> partition_size(2,0);
1312 
1313  unsigned int partition = 0;
1314  // Here, we do not block inside the connectivity graph
1315  //blocking_connectivity = false;
1316 
1317  // Make the partitioning of the first layer of the blocks of cells.
1318  make_partitioning( connectivity, cluster_size, cell_partition,
1319  partition_list, partition_size, partition);
1320 
1321  // Partition within partitions.
1322  make_partitioning_within_partitions_post_blocked
1323  (connectivity, cell_active_fe_index, partition, cluster_size, hp_bool,
1324  cell_partition,
1325  partition_list, partition_size,
1326  partition_partition_list,
1327  irregular_cells);
1328 
1329  partition_list.swap(renumbering);
1330 
1331  for (unsigned int j=0; j<renumbering.size(); j++)
1332  renumbering[j] = partition_list[partition_partition_list[j]];
1333 
1334  for (unsigned int i=0; i<n_ghost_cells; ++i)
1335  renumbering.push_back(i+n_active_cells);
1336 
1337  update_task_info(partition);
1338 
1339  }
1340 
1341 
1342 
1343  void
1345  (const std::vector<unsigned char> &irregular_cells,
1346  const DynamicSparsityPattern &connectivity_cells,
1347  DynamicSparsityPattern &connectivity_blocks) const
1348  {
1349  std::vector<std::vector<unsigned int> > cell_blocks(n_blocks);
1350  std::vector<unsigned int> touched_cells(n_active_cells);
1351  unsigned int cell = 0;
1352  for (unsigned int i=0, mcell=0; i<n_blocks; ++i)
1353  {
1354  for (unsigned int c=0; c<block_size &&
1355  mcell < *(cell_partition_data.end()-2); ++c, ++mcell)
1356  {
1357  unsigned int ncomp = (irregular_cells[mcell]>0)
1358  ?irregular_cells[mcell]:vectorization_length;
1359  for (unsigned int c=0; c<ncomp; ++c, ++cell)
1360  {
1361  cell_blocks[i].push_back(cell);
1362  touched_cells[cell] = i;
1363  }
1364  }
1365  }
1366  AssertDimension(cell, n_active_cells);
1367  for (unsigned int i=0; i<cell_blocks.size(); ++i)
1368  for (unsigned int col=0; col<cell_blocks[i].size(); ++col)
1369  {
1371  = connectivity_cells.begin(cell_blocks[i][col]);
1372  it != connectivity_cells.end(cell_blocks[i][col]); ++it)
1373  {
1374  if (touched_cells[it->column()] != i)
1375  connectivity_blocks.add(i,touched_cells[it->column()]);
1376  }
1377  }
1378  }
1379 
1380 
1381 
1382 
1383  // Function to create partitioning on the second layer within each
1384  // partition. Version without preblocking.
1385  void
1387  (const DynamicSparsityPattern &connectivity,
1388  const std::vector<unsigned int> &cell_active_fe_index,
1389  const unsigned int partition,
1390  const unsigned int cluster_size,
1391  const bool hp_bool,
1392  const std::vector<unsigned int> &cell_partition,
1393  const std::vector<unsigned int> &partition_list,
1394  const std::vector<unsigned int> &partition_size,
1395  std::vector<unsigned int> &partition_partition_list,
1396  std::vector<unsigned char> &irregular_cells)
1397  {
1398 
1399  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
1400  const unsigned int n_ghost_slots =
1401  *(cell_partition_data.end()-1)-n_macro_cells;
1402 
1403  // List of cells in previous partition
1404  std::vector<unsigned int> neighbor_list;
1405  // List of cells in current partition for use as neighbors in next partition
1406  std::vector<unsigned int> neighbor_neighbor_list;
1407 
1408  std::vector<unsigned int> renumbering(n_active_cells);
1409 
1410  irregular_cells.back() = 0;
1411  irregular_cells.resize(n_active_cells+n_ghost_slots);
1412 
1413  unsigned int max_fe_index = 0;
1414  for (unsigned int i=0; i<cell_active_fe_index.size(); ++i)
1415  max_fe_index = std::max(cell_active_fe_index[i], max_fe_index);
1416  Assert(!hp_bool || cell_active_fe_index.size() == n_active_cells,
1417  ExcInternalError());
1418 
1419  {
1420  unsigned int n_macro_cells_before = 0;
1421  // Create partitioning within partitions.
1422 
1423  // For each block of cells, this variable saves to which partitions
1424  // the block belongs. Initialize all to n_macro_cells to mark them as
1425  // not yet assigned a partition.
1426  std::vector<unsigned int> cell_partition_l2(n_active_cells,
1428  partition_row_index.clear();
1429  partition_row_index.resize(partition+1,0);
1430  cell_partition_data.resize(1,0);
1431 
1432  unsigned int counter = 0;
1433  unsigned int missing_macros;
1434  for (unsigned int part=0; part<partition; ++part)
1435  {
1436  neighbor_neighbor_list.resize(0);
1437  neighbor_list.resize(0);
1438  bool work = true;
1439  unsigned int partition_l2 = 0;
1440  unsigned int start_up = partition_size[part];
1441  unsigned int partition_counter = 0;
1442  while (work)
1443  {
1444  if (neighbor_list.size()==0)
1445  {
1446  work = false;
1447  partition_counter = 0;
1448  for (unsigned int j=start_up; j<partition_size[part+1]; ++j)
1449  if (cell_partition[partition_list[j]] == part &&
1450  cell_partition_l2[partition_list[j]] == numbers::invalid_unsigned_int)
1451  {
1452  start_up = j;
1453  work = true;
1454  partition_counter = 1;
1455  // To start up, set the start_up cell to partition
1456  // and list all its neighbors.
1457  AssertIndexRange (start_up, partition_size[part+1]);
1458  cell_partition_l2[partition_list[start_up]] =
1459  partition_l2;
1460  neighbor_neighbor_list.push_back
1461  (partition_list[start_up]);
1462  partition_partition_list[counter++] =
1463  partition_list[start_up];
1464  start_up++;
1465  break;
1466  }
1467  }
1468  else
1469  {
1470  partition_counter = 0;
1471  for (unsigned int j=0; j<neighbor_list.size(); ++j)
1472  {
1473  Assert(cell_partition[neighbor_list[j]]==part,
1474  ExcInternalError());
1475  Assert(cell_partition_l2[neighbor_list[j]]==partition_l2-1,
1476  ExcInternalError());
1478  connectivity.begin(neighbor_list[j]),
1479  end = connectivity.end(neighbor_list[j]);
1480  for (; neighbor!=end ; ++neighbor)
1481  {
1482  if (cell_partition[neighbor->column()] == part &&
1483  cell_partition_l2[neighbor->column()]==
1485  {
1486  cell_partition_l2[neighbor->column()] = partition_l2;
1487  neighbor_neighbor_list.push_back(neighbor->column());
1488  partition_partition_list[counter++] = neighbor->column();
1489  partition_counter++;
1490  }
1491  }
1492  }
1493  }
1494  if (partition_counter>0)
1495  {
1496  int index_before = neighbor_neighbor_list.size(),
1497  index = index_before;
1498  {
1499  // put the cells into separate lists for each FE index
1500  // within one partition-partition
1501  missing_macros = 0;
1502  std::vector<unsigned int> remaining_per_macro_cell
1503  (max_fe_index+1);
1504  std::vector<std::vector<unsigned int> >
1505  renumbering_fe_index;
1506  unsigned int cell;
1507  bool filled = true;
1508  if (hp_bool == true)
1509  {
1510  renumbering_fe_index.resize(max_fe_index+1);
1511  for (cell=counter-partition_counter; cell<counter; ++cell)
1512  {
1513  renumbering_fe_index
1514  [cell_active_fe_index.empty() ? 0 :
1515  cell_active_fe_index[partition_partition_list
1516  [cell]]].
1517  push_back(partition_partition_list[cell]);
1518  }
1519  // check how many more cells are needed in the lists
1520  for (unsigned int j=0; j<max_fe_index+1; j++)
1521  {
1522  remaining_per_macro_cell[j] =
1523  renumbering_fe_index[j].size()%vectorization_length;
1524  if (remaining_per_macro_cell[j] != 0)
1525  filled = false;
1526  missing_macros += ((renumbering_fe_index[j].size()+
1527  vectorization_length-1)/vectorization_length);
1528  }
1529  }
1530  else
1531  {
1532  remaining_per_macro_cell.resize(1);
1533  remaining_per_macro_cell[0] = partition_counter%
1534  vectorization_length;
1535  missing_macros = partition_counter/vectorization_length;
1536  if (remaining_per_macro_cell[0] != 0)
1537  {
1538  filled = false;
1539  missing_macros++;
1540  }
1541  }
1542  missing_macros = cluster_size - (missing_macros%cluster_size);
1543 
1544  // now we realized that there are some cells missing.
1545  while (missing_macros>0 || filled == false)
1546  {
1547  if (index==0)
1548  {
1549  index = neighbor_neighbor_list.size();
1550  if (index == index_before)
1551  {
1552  if (missing_macros != 0)
1553  {
1554  neighbor_neighbor_list.resize(0);
1555  }
1556  start_up--;
1557  break;// not connected - start again
1558  }
1559  index_before = index;
1560  }
1561  index--;
1562  unsigned int additional = neighbor_neighbor_list
1563  [index];
1564 
1565  // go through the neighbors of the last cell in the
1566  // current partition and check if we find some to
1567  // fill up with.
1569  neighbor = connectivity.begin(additional),
1570  end = connectivity.end(additional);
1571  for (; neighbor!=end ; ++neighbor)
1572  {
1573  if (cell_partition[neighbor->column()] == part &&
1574  cell_partition_l2[neighbor->column()] ==
1576  {
1577  unsigned int this_index = 0;
1578  if (hp_bool == true)
1579  this_index = cell_active_fe_index.empty() ? 0 :
1580  cell_active_fe_index[neighbor->column()];
1581 
1582  // Only add this cell if we need more macro
1583  // cells in the current block or if there is
1584  // a macro cell with the FE index that is
1585  // not yet fully populated
1586  if (missing_macros > 0 ||
1587  remaining_per_macro_cell[this_index] > 0)
1588  {
1589  cell_partition_l2[neighbor->column()] = partition_l2;
1590  neighbor_neighbor_list.push_back(neighbor->column());
1591  if (hp_bool == true)
1592  renumbering_fe_index[this_index].
1593  push_back(neighbor->column());
1594  partition_partition_list[counter] =
1595  neighbor->column();
1596  counter++;
1597  partition_counter++;
1598  if (remaining_per_macro_cell[this_index]
1599  == 0 && missing_macros > 0)
1600  missing_macros--;
1601  remaining_per_macro_cell[this_index]++;
1602  if (remaining_per_macro_cell[this_index]
1603  == vectorization_length)
1604  {
1605  remaining_per_macro_cell[this_index] = 0;
1606  }
1607  if (missing_macros == 0)
1608  {
1609  filled = true;
1610  for (unsigned int fe_ind=0;
1611  fe_ind<max_fe_index+1; ++fe_ind)
1612  if (remaining_per_macro_cell[fe_ind]!=0)
1613  filled = false;
1614  }
1615  if (filled == true)
1616  break;
1617  }
1618  }
1619  }
1620  }
1621  if (hp_bool == true)
1622  {
1623  // set the renumbering according to their active FE
1624  // index within one partition-partition which was
1625  // implicitly assumed above
1626  cell = counter - partition_counter;
1627  for (unsigned int j=0; j<max_fe_index+1; j++)
1628  {
1629  for (unsigned int jj=0; jj<renumbering_fe_index[j].
1630  size(); jj++)
1631  renumbering[cell++] =
1632  renumbering_fe_index[j][jj];
1633  if (renumbering_fe_index[j].size()%vectorization_length != 0)
1634  irregular_cells[renumbering_fe_index[j].size()/
1635  vectorization_length+
1636  n_macro_cells_before] =
1637  renumbering_fe_index[j].size()%vectorization_length;
1638  n_macro_cells_before += (renumbering_fe_index[j].
1639  size()+vectorization_length-1)/
1640  vectorization_length;
1641  renumbering_fe_index[j].resize(0);
1642  }
1643  }
1644  else
1645  {
1646  n_macro_cells_before += partition_counter/vectorization_length;
1647  if (partition_counter%vectorization_length != 0)
1648  {
1649  irregular_cells[n_macro_cells_before] =
1650  partition_counter%vectorization_length;
1651  n_macro_cells_before++;
1652  }
1653  }
1654  }
1655  cell_partition_data.
1656  push_back(n_macro_cells_before);
1657  partition_l2++;
1658  }
1659  neighbor_list = neighbor_neighbor_list;
1660  neighbor_neighbor_list.resize(0);
1661  }
1662  partition_row_index[part+1] =
1663  partition_row_index[part] + partition_l2;
1664  }
1665  }
1666  if (hp_bool == true)
1667  {
1668  partition_partition_list.swap(renumbering);
1669  }
1670 
1671  }
1672 
1673 
1674 
1675  // Function to create coloring on the second layer within each partition. Version assumes preblocking.
1676  void
1678  (const DynamicSparsityPattern &connectivity,
1679  const unsigned int partition,
1680  const std::vector<unsigned int> &cell_partition,
1681  const std::vector<unsigned int> &partition_list,
1682  const std::vector<unsigned int> &partition_size,
1683  std::vector<unsigned int> &partition_color_list)
1684  {
1685  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
1686  std::vector<unsigned int> cell_color(n_blocks, n_macro_cells);
1687  std::vector<bool> color_finder;
1688 
1689  partition_row_index.resize(partition+1);
1690  cell_partition_data.clear();
1691  unsigned int color_counter = 0, index_counter = 0;
1692  for (unsigned int part=0; part<partition; part++)
1693  {
1694  partition_row_index[part] = index_counter;
1695  unsigned int max_color = 0;
1696  for (unsigned int k=partition_size[part]; k<partition_size[part+1];
1697  k++)
1698  {
1699  unsigned int cell = partition_list[k];
1700  unsigned int n_neighbors = connectivity.row_length(cell);
1701 
1702  // In the worst case, each neighbor has a different color. So we
1703  // find at least one available color between 0 and n_neighbors.
1704  color_finder.resize(n_neighbors+1);
1705  for (unsigned int j=0; j<=n_neighbors; ++j)
1706  color_finder[j]=true;
1708  neighbor = connectivity.begin(cell),
1709  end = connectivity.end(cell);
1710  for (; neighbor!=end ; ++neighbor)
1711  {
1712  // Mark the color that a neighbor within the partition has
1713  // as taken
1714  if (cell_partition[neighbor->column()] == part &&
1715  cell_color[neighbor->column()] <= n_neighbors)
1716  color_finder[cell_color[neighbor->column()]] = false;
1717  }
1718  // Choose the smallest color that is not taken for the block
1719  cell_color[cell]=0;
1720  while (color_finder[cell_color[cell]] == false)
1721  cell_color[cell]++;
1722  if (cell_color[cell] > max_color)
1723  max_color = cell_color[cell];
1724  }
1725  // Reorder within partition: First, all blocks that belong the 0 and
1726  // then so on until those with color max (Note that the smaller the
1727  // number the larger the partition)
1728  for (unsigned int color=0; color<=max_color; color++)
1729  {
1730  cell_partition_data.push_back(color_counter);
1731  index_counter++;
1732  for (unsigned int k=partition_size[part];
1733  k<partition_size[part+1]; k++)
1734  {
1735  unsigned int cell=partition_list[k];
1736  if (cell_color[cell] == color)
1737  {
1738  partition_color_list[color_counter++] = cell;
1739  }
1740  }
1741  }
1742  }
1743  cell_partition_data.push_back(n_blocks);
1744  partition_row_index[partition] = index_counter;
1745  AssertDimension (color_counter, n_blocks);
1746  }
1747 
1748 
1749  // Function to create partitioning on the first layer.
1750  void
1752  (const DynamicSparsityPattern &connectivity,
1753  const unsigned int cluster_size,
1754  std::vector<unsigned int> &cell_partition,
1755  std::vector<unsigned int> &partition_list,
1756  std::vector<unsigned int> &partition_size,
1757  unsigned int &partition) const
1758 
1759  {
1760  // For each block of cells, this variable saves to which partitions the
1761  // block belongs. Initialize all to n_macro_cells to mark them as not
1762  // yet assigned a partition.
1763  //std::vector<unsigned int> cell_partition (n_active_cells,
1764  // numbers::invalid_unsigned_int);
1765  // List of cells in previous partition
1766  std::vector<unsigned int> neighbor_list;
1767  // List of cells in current partition for use as neighbors in next partition
1768  std::vector<unsigned int> neighbor_neighbor_list;
1769 
1770  // In element j of this variable, one puts the old number of the block
1771  // that should be the jth block in the new numeration.
1772  //std::vector<unsigned int> partition_list(n_active_cells,0);
1773 
1774  // This vector points to the start of each partition.
1775  //std::vector<unsigned int> partition_size(2,0);
1776 
1777  partition = 0;
1778  unsigned int counter=0;
1779  unsigned int start_nonboundary = cell_partition_data.size() == 5 ?
1780  vectorization_length * (cell_partition_data[2] -
1781  cell_partition_data[1]) : 0;
1782 
1783  const unsigned int n_macro_cells = *(cell_partition_data.end()-2);
1784  if (n_macro_cells == 0)
1785  return;
1786  if (scheme == color)
1787  start_nonboundary = n_macro_cells;
1788  if ( scheme == partition_color || scheme == color ) // blocking_connectivity == true
1789  start_nonboundary = ((start_nonboundary+block_size-1)
1790  /block_size);
1791  unsigned int n_blocks;
1792  if ( scheme == partition_color || scheme == color ) // blocking_connectivity == true
1793  n_blocks = this->n_blocks;
1794  else
1795  n_blocks = n_active_cells;
1796 
1797  if (start_nonboundary > n_blocks)
1798  start_nonboundary = n_blocks;
1799 
1800 
1801  unsigned int start_up = 0;
1802  bool work = true;
1803  unsigned int remainder = cluster_size;
1804 
1805  // this performs a classical breath-first search in the connectivity
1806  // graph of the cells under the restriction that the size of the
1807  // partitions should be a multiple of the given block size
1808  while (work)
1809  {
1810  // put the cells with neighbors on remote MPI processes up front
1811  if (start_nonboundary>0)
1812  {
1813  for (unsigned int cell=0; cell<start_nonboundary; ++cell)
1814  {
1815  const unsigned int cell_nn = cell;
1816  cell_partition[cell_nn] = partition;
1817  neighbor_list.push_back(cell_nn);
1818  partition_list[counter++] = cell_nn;
1819  partition_size.back()++;
1820  }
1821  start_nonboundary = 0;
1822  remainder -= (start_nonboundary%cluster_size);
1823  if (remainder == cluster_size)
1824  remainder = 0;
1825  }
1826  else
1827  {
1828  // To start up, set the start_up cell to partition and list all
1829  // its neighbors.
1830  cell_partition[start_up] = partition;
1831  neighbor_list.push_back(start_up);
1832  partition_list[counter++] = start_up;
1833  partition_size.back()++;
1834  start_up++;
1835  remainder--;
1836  if (remainder == cluster_size)
1837  remainder = 0;
1838  }
1839  int index_before = neighbor_list.size(), index = index_before,
1840  index_stop = 0;
1841  while (remainder>0)
1842  {
1843  if (index==index_stop)
1844  {
1845  index = neighbor_list.size();
1846  if (index == index_before)
1847  {
1848  neighbor_list.resize(0);
1849  goto not_connect;
1850  }
1851  index_stop = index_before;
1852  index_before = index;
1853  }
1854  index--;
1855  unsigned int additional = neighbor_list[index];
1857  connectivity.begin(additional),
1858  end = connectivity.end(additional);
1859  for (; neighbor!=end ; ++neighbor)
1860  {
1861  if (cell_partition[neighbor->column()]==numbers::invalid_unsigned_int)
1862  {
1863  partition_size.back()++;
1864  cell_partition[neighbor->column()] = partition;
1865  neighbor_list.push_back(neighbor->column());
1866  partition_list[counter++] = neighbor->column();
1867  remainder--;
1868  if (remainder == 0)
1869  break;
1870  }
1871  }
1872  }
1873 
1874  while (neighbor_list.size()>0)
1875  {
1876  partition++;
1877 
1878  // counter for number of cells so far in current partition
1879  unsigned int partition_counter = 0;
1880 
1881  // Mark the start of the new partition
1882  partition_size.push_back(partition_size.back());
1883 
1884  // Loop through the list of cells in previous partition and put
1885  // all their neighbors in current partition
1886  for (unsigned int j=0; j<neighbor_list.size(); ++j)
1887  {
1888  Assert(cell_partition[neighbor_list[j]]==partition-1,
1889  ExcInternalError());
1891  connectivity.begin(neighbor_list[j]),
1892  end = connectivity.end(neighbor_list[j]);
1893  for (; neighbor!=end ; ++neighbor)
1894  {
1895  if (cell_partition[neighbor->column()]==numbers::invalid_unsigned_int)
1896  {
1897  partition_size.back()++;
1898  cell_partition[neighbor->column()] = partition;
1899 
1900  // collect the cells of the current partition for
1901  // use as neighbors in next partition
1902  neighbor_neighbor_list.push_back(neighbor->column());
1903  partition_list[counter++] = neighbor->column();
1904  partition_counter++;
1905  }
1906  }
1907  }
1908  remainder = cluster_size-(partition_counter%cluster_size);
1909  if (remainder == cluster_size)
1910  remainder = 0;
1911  int index_stop = 0;
1912  int index_before = neighbor_neighbor_list.size(), index = index_before;
1913  while (remainder>0)
1914  {
1915  if (index==index_stop)
1916  {
1917  index = neighbor_neighbor_list.size();
1918  if (index == index_before)
1919  {
1920  neighbor_neighbor_list.resize(0);
1921  break;
1922  }
1923  index_stop = index_before;
1924  index_before = index;
1925  }
1926  index--;
1927  unsigned int additional = neighbor_neighbor_list[index];
1929  connectivity.begin(additional),
1930  end = connectivity.end(additional);
1931  for (; neighbor!=end ; ++neighbor)
1932  {
1933  if (cell_partition[neighbor->column()]==numbers::invalid_unsigned_int)
1934  {
1935  partition_size.back()++;
1936  cell_partition[neighbor->column()] = partition;
1937  neighbor_neighbor_list.push_back(neighbor->column());
1938  partition_list[counter++] = neighbor->column();
1939  remainder--;
1940  if (remainder == 0)
1941  break;
1942  }
1943  }
1944  }
1945 
1946  neighbor_list = neighbor_neighbor_list;
1947  neighbor_neighbor_list.resize(0);
1948  }
1949 not_connect:
1950  // One has to check if the graph is not connected so we have to find
1951  // another partition.
1952  work = false;
1953  for (unsigned int j=start_up; j<n_blocks; ++j)
1954  if (cell_partition[j] == numbers::invalid_unsigned_int)
1955  {
1956  start_up = j;
1957  work = true;
1958  if (remainder == 0)
1959  remainder = cluster_size;
1960  break;
1961  }
1962  }
1963  if (remainder != 0)
1964  partition++;
1965 
1966  AssertDimension (partition_size[partition], n_blocks);
1967 
1968  }
1969 
1970 
1971  void
1973  (const unsigned int partition)
1974  {
1975  evens = (partition+1)/2;
1976  odds = partition/2;
1977  n_blocked_workers =
1978  odds-(odds+evens+1)%2;
1979  n_workers = evens+odds-
1980  n_blocked_workers;
1981  // From here only used for partition partition option.
1982  partition_evens.resize(partition);
1983  partition_odds.resize(partition);
1984  partition_n_blocked_workers.resize(partition);
1985  partition_n_workers.resize(partition);
1986  for (unsigned int part=0; part<partition; part++)
1987  {
1988  partition_evens[part] =
1989  (partition_row_index[part+1]-
1990  partition_row_index[part]+1)/2;
1991  partition_odds[part] =
1992  (partition_row_index[part+1]-
1993  partition_row_index[part])/2;
1994  partition_n_blocked_workers[part] =
1995  partition_odds[part]-(partition_odds[part]+
1996  partition_evens[part]+1)%2;
1997  partition_n_workers[part] =
1998  partition_evens[part]+partition_odds[part]-
1999  partition_n_blocked_workers[part];
2000  }
2001  }
2002  }
2003 }
2004 
2005 
2006 
2007 // explicit instantiations of template functions
2008 template void internal::MatrixFreeFunctions::TaskInfo::
2009 print_memory_statistics<std::ostream> (std::ostream &, const std::size_t) const;
2010 template void internal::MatrixFreeFunctions::TaskInfo::
2011 print_memory_statistics<ConditionalOStream> (ConditionalOStream &, const std::size_t) const;
2012 
2013 
2014 DEAL_II_NAMESPACE_CLOSE
static const unsigned int invalid_unsigned_int
Definition: types.h:173
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1248
virtual void cell(const std::pair< unsigned int, unsigned int > &cell_range)=0
void loop(MFWorkerInterface &worker) const
Definition: task_info.cc:324
void add(const size_type i, const size_type j)
void guess_block_size(const unsigned int dofs_per_cell)
Definition: task_info.cc:945
std::vector< unsigned int > partition_row_index
Definition: task_info.h:436
#define AssertIndexRange(index, range)
Definition: exceptions.h:1284
std::vector< unsigned int > partition_n_workers
Definition: task_info.h:507
virtual void vector_update_ghosts_finish()=0
Finishes the communication for the update ghost values operation.
std::vector< unsigned int > cell_partition_data
Definition: task_info.h:444
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
void make_connectivity_cells_to_blocks(const std::vector< unsigned char > &irregular_cells, const DynamicSparsityPattern &connectivity_cells, DynamicSparsityPattern &connectivity_blocks) const
Definition: task_info.cc:1345
std::vector< unsigned int > partition_n_blocked_workers
Definition: task_info.h:501
void make_partitioning_within_partitions_post_blocked(const DynamicSparsityPattern &connectivity, const std::vector< unsigned int > &cell_active_fe_index, const unsigned int partition, const unsigned int cluster_size, const bool hp_bool, const std::vector< unsigned int > &cell_partition, const std::vector< unsigned int > &partition_list, const std::vector< unsigned int > &partition_size, std::vector< unsigned int > &partition_partition_list, std::vector< unsigned char > &irregular_cells)
Definition: task_info.cc:1387
void make_coloring_within_partitions_pre_blocked(const DynamicSparsityPattern &connectivity, const unsigned int partition, const std::vector< unsigned int > &cell_partition, const std::vector< unsigned int > &partition_list, const std::vector< unsigned int > &partition_size, std::vector< unsigned int > &partition_color_list)
Definition: task_info.cc:1678
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 make_thread_graph_partition_color(DynamicSparsityPattern &connectivity, std::vector< unsigned int > &renumbering, std::vector< unsigned char > &irregular_cells, const bool hp_bool)
Definition: task_info.cc:975
void update_task_info(const unsigned int partition)
Definition: task_info.cc:1973
std::vector< unsigned int > boundary_partition_data
Definition: task_info.h:462
void initial_setup_blocks_tasks(const std::vector< unsigned int > &boundary_cells, std::vector< unsigned int > &renumbering, std::vector< unsigned char > &incompletely_filled_vectorization)
Definition: task_info.cc:886
virtual void zero_dst_vector_range(const unsigned int range_index)=0
virtual void boundary(const std::pair< unsigned int, unsigned int > &face_range)=0
void create_blocks_serial(const std::vector< unsigned int > &boundary_cells, const std::vector< unsigned int > &cells_close_to_boundary, const unsigned int dofs_per_cell, const std::vector< unsigned int > &cell_vectorization_categories, const bool cell_vectorization_categories_strict, std::vector< unsigned int > &renumbering, std::vector< unsigned char > &incompletely_filled_vectorization)
Definition: task_info.cc:701
std::vector< unsigned int > invert_permutation(const std::vector< unsigned int > &permutation)
Definition: utilities.cc:509
virtual void vector_update_ghosts_start()=0
Starts the communication for the update ghost values operation.
virtual void face(const std::pair< unsigned int, unsigned int > &face_range)=0
std::vector< unsigned int > face_partition_data
Definition: task_info.h:453
void collect_boundary_cells(const unsigned int n_active_cells, const unsigned int n_active_and_ghost_cells, const unsigned int vectorization_length, std::vector< unsigned int > &boundary_cells)
Definition: task_info.cc:630
size_type row_length(const size_type row) const
void make_thread_graph_partition_partition(const std::vector< unsigned int > &cell_active_fe_index, DynamicSparsityPattern &connectivity, std::vector< unsigned int > &renumbering, std::vector< unsigned char > &irregular_cells, const bool hp_bool)
Definition: task_info.cc:1284
void make_partitioning(const DynamicSparsityPattern &connectivity, const unsigned int cluster_size, std::vector< unsigned int > &cell_partition, std::vector< unsigned int > &partition_list, std::vector< unsigned int > &partition_size, unsigned int &partition) const
Definition: task_info.cc:1752
virtual void vector_compress_start()=0
Starts the communication for the vector compress operation.
std::vector< unsigned int > partition_odds
Definition: task_info.h:495
std::size_t memory_consumption() const
Definition: task_info.cc:614
static ::ExceptionBase & ExcNotImplemented()
static unsigned int n_threads()
MinMaxAvg min_max_avg(const double my_value, const MPI_Comm &mpi_communicator)
Definition: mpi.cc:275
std::vector< unsigned int > partition_evens
Definition: task_info.h:489
void print_memory_statistics(StreamType &out, std::size_t data_length) const
Definition: task_info.cc:599
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
static ::ExceptionBase & ExcInternalError()
void make_thread_graph(const std::vector< unsigned int > &cell_active_fe_index, DynamicSparsityPattern &connectivity, std::vector< unsigned int > &renumbering, std::vector< unsigned char > &irregular_cells, const bool hp_bool)
Definition: task_info.cc:1110
virtual void vector_compress_finish()=0
Finishes the communication for the vector compress operation.