1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2020 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15
16
17 #ifndef dealii_mg_transfer_global_coarsening_templates_h
18 #define dealii_mg_transfer_global_coarsening_templates_h
19
20 #include <deal.II/base/config.h>
21
22 #include <deal.II/base/mpi_compute_index_owner_internal.h>
23 #include <deal.II/base/mpi_consensus_algorithms.h>
24
25 #include <deal.II/dofs/dof_handler.h>
26 #include <deal.II/dofs/dof_tools.h>
27
28 #include <deal.II/fe/fe_tools.h>
29
30 #include <deal.II/hp/dof_handler.h>
31
32 #include <deal.II/matrix_free/evaluation_kernels.h>
33 #include <deal.II/matrix_free/fe_evaluation.h>
34
35 #include <deal.II/multigrid/mg_transfer_global_coarsening.h>
36
37 DEAL_II_NAMESPACE_OPEN
38
39 namespace
40 {
41 /**
42 * Helper class to select the right templated implementation.
43 *
44 * @note This class is similar to internal::FEEvaluationFactory
45 */
46 class CellTransferFactory
47 {
48 public:
49 static const unsigned int max_degree = 9;
50
CellTransferFactory(const unsigned int degree_fine,const unsigned int degree_coarse)51 CellTransferFactory(const unsigned int degree_fine,
52 const unsigned int degree_coarse)
53 : degree_fine(degree_fine)
54 , degree_coarse(degree_coarse)
55 {}
56
57 template <typename Fu, unsigned int deg = 1>
58 bool
run(Fu & fu)59 run(Fu &fu)
60 {
61 if ((degree_fine == (2 * deg + 1)) && (degree_coarse == deg))
62 fu.template run<2 * deg + 1, deg>(); // h-MG
63 else if ((degree_fine == deg) && (degree_coarse == std::max(deg / 2, 1u)))
64 fu.template run<deg, std::max(deg / 2u, 1u)>(); // p-MG: bisection
65 else if ((degree_fine == deg) && (degree_coarse == deg))
66 fu.template run<deg, deg>(); // identity (nothing to do)
67 else if ((degree_fine == deg) && (degree_coarse == std::max(deg - 1, 1u)))
68 fu.template run<deg, std::max(deg - 1u, 1u)>(); // p-MG: --
69 else if ((degree_fine == deg) && (degree_coarse == 1))
70 fu.template run<deg, 1>(); // p-MG: jump to 1
71 else if (deg < max_degree)
72 return run<Fu, std::min(deg + 1, max_degree)>(fu); // try next degree
73 else
74 {
75 // no match -> slow path
76 fu.template run<-1, -1>(degree_fine, degree_coarse);
77 return false; // indicate that slow path has been taken
78 }
79
80 return true; // indicate that fast path has been taken
81 }
82
83 private:
84 const unsigned int degree_fine;
85 const unsigned int degree_coarse;
86 };
87
88 /**
89 * Helper class containing the cell-wise prolongation operation.
90 */
91 template <int dim, typename Number>
92 class CellProlongator
93 {
94 public:
CellProlongator(const AlignedVector<Number> & prolongation_matrix_1d,const Number * evaluation_data_coarse,Number * evaluation_data_fine)95 CellProlongator(const AlignedVector<Number> &prolongation_matrix_1d,
96 const Number * evaluation_data_coarse,
97 Number * evaluation_data_fine)
98 : prolongation_matrix_1d(prolongation_matrix_1d)
99 , evaluation_data_coarse(evaluation_data_coarse)
100 , evaluation_data_fine(evaluation_data_fine)
101 {}
102
103 template <int degree_fine, int degree_coarse>
104 void
105 run(const unsigned int degree_fine_ = numbers::invalid_unsigned_int,
106 const unsigned int degree_coarse_ = numbers::invalid_unsigned_int)
107 {
108 internal::FEEvaluationImplBasisChange<
109 internal::evaluate_general,
110 internal::EvaluatorQuantity::value,
111 dim,
112 degree_coarse + 1,
113 degree_fine + 1,
114 Number,
115 Number>::do_forward(1,
116 prolongation_matrix_1d,
117 evaluation_data_coarse,
118 evaluation_data_fine,
119 degree_coarse_ + 1,
120 degree_fine_ + 1);
121 }
122
123 private:
124 const AlignedVector<Number> &prolongation_matrix_1d;
125 const Number * evaluation_data_coarse;
126 Number * evaluation_data_fine;
127 };
128
129 /**
130 * Helper class containing the cell-wise restriction operation.
131 */
132 template <int dim, typename Number>
133 class CellRestrictor
134 {
135 public:
CellRestrictor(const AlignedVector<Number> & prolongation_matrix_1d,Number * evaluation_data_fine,Number * evaluation_data_coarse)136 CellRestrictor(const AlignedVector<Number> &prolongation_matrix_1d,
137 Number * evaluation_data_fine,
138 Number * evaluation_data_coarse)
139 : prolongation_matrix_1d(prolongation_matrix_1d)
140 , evaluation_data_fine(evaluation_data_fine)
141 , evaluation_data_coarse(evaluation_data_coarse)
142 {}
143
144 template <int degree_fine, int degree_coarse>
145 void
146 run(const unsigned int degree_fine_ = numbers::invalid_unsigned_int,
147 const unsigned int degree_coarse_ = numbers::invalid_unsigned_int)
148 {
149 internal::FEEvaluationImplBasisChange<
150 internal::evaluate_general,
151 internal::EvaluatorQuantity::value,
152 dim,
153 degree_coarse == 0 ? -1 : (degree_coarse + 1),
154 degree_fine == 0 ? -1 : (degree_fine + 1),
155 Number,
156 Number>::do_backward(1,
157 prolongation_matrix_1d,
158 false,
159 evaluation_data_fine,
160 evaluation_data_coarse,
161 degree_coarse_ + 1,
162 degree_fine_ + 1);
163 }
164
165 private:
166 const AlignedVector<Number> &prolongation_matrix_1d;
167 Number * evaluation_data_fine;
168 Number * evaluation_data_coarse;
169 };
170
171 class CellProlongatorTest
172 {
173 public:
174 template <int degree_fine, int degree_coarse>
175 void
176 run(const unsigned int = numbers::invalid_unsigned_int,
177 const unsigned int = numbers::invalid_unsigned_int)
178 {}
179 };
180
181 } // namespace
182
183
184
185 namespace internal
186 {
187 namespace
188 {
189 template <typename MeshType>
190 MPI_Comm
get_mpi_comm(const MeshType & mesh)191 get_mpi_comm(const MeshType &mesh)
192 {
193 const auto *tria_parallel = dynamic_cast<
194 const dealii::parallel::TriangulationBase<MeshType::dimension,
195 MeshType::space_dimension> *>(
196 &(mesh.get_triangulation()));
197
198 return tria_parallel != nullptr ? tria_parallel->get_communicator() :
199 MPI_COMM_SELF;
200 }
201
202 template <int dim>
203 unsigned int
compute_shift_within_children(const unsigned int child,const unsigned int fe_shift_1d,const unsigned int fe_degree)204 compute_shift_within_children(const unsigned int child,
205 const unsigned int fe_shift_1d,
206 const unsigned int fe_degree)
207 {
208 // we put the degrees of freedom of all child cells in lexicographic
209 // ordering
210 unsigned int c_tensor_index[dim];
211 unsigned int tmp = child;
212 for (unsigned int d = 0; d < dim; ++d)
213 {
214 c_tensor_index[d] = tmp % 2;
215 tmp /= 2;
216 }
217 const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
218 unsigned int factor = 1;
219 unsigned int shift = fe_shift_1d * c_tensor_index[0];
220 for (unsigned int d = 1; d < dim; ++d)
221 {
222 factor *= n_child_dofs_1d;
223 shift = shift + factor * fe_shift_1d * c_tensor_index[d];
224 }
225 return shift;
226 }
227
228 template <int dim>
229 void
get_child_offset(const unsigned int child,const unsigned int fe_shift_1d,const unsigned int fe_degree,std::vector<unsigned int> & local_dof_indices)230 get_child_offset(const unsigned int child,
231 const unsigned int fe_shift_1d,
232 const unsigned int fe_degree,
233 std::vector<unsigned int> &local_dof_indices)
234 {
235 const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
236 const unsigned int shift =
237 compute_shift_within_children<dim>(child, fe_shift_1d, fe_degree);
238 const unsigned int n_components =
239 local_dof_indices.size() / Utilities::fixed_power<dim>(fe_degree + 1);
240 const unsigned int n_scalar_cell_dofs =
241 Utilities::fixed_power<dim>(n_child_dofs_1d);
242 for (unsigned int c = 0, m = 0; c < n_components; ++c)
243 for (unsigned int k = 0; k < (dim > 2 ? (fe_degree + 1) : 1); ++k)
244 for (unsigned int j = 0; j < (dim > 1 ? (fe_degree + 1) : 1); ++j)
245 for (unsigned int i = 0; i < (fe_degree + 1); ++i, ++m)
246 local_dof_indices[m] = c * n_scalar_cell_dofs +
247 k * n_child_dofs_1d * n_child_dofs_1d +
248 j * n_child_dofs_1d + i + shift;
249 }
250
251 template <int dim>
252 std::vector<std::vector<unsigned int>>
get_child_offsets(const unsigned int dofs_per_cell_coarse,const unsigned int fe_shift_1d,const unsigned int fe_degree)253 get_child_offsets(const unsigned int dofs_per_cell_coarse,
254 const unsigned int fe_shift_1d,
255 const unsigned int fe_degree)
256 {
257 std::vector<std::vector<unsigned int>> cell_local_chilren_indices(
258 GeometryInfo<dim>::max_children_per_cell,
259 std::vector<unsigned int>(dofs_per_cell_coarse));
260 {
261 for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
262 c++)
263 get_child_offset<dim>(c,
264 fe_shift_1d,
265 fe_degree,
266 cell_local_chilren_indices[c]);
267 }
268 return cell_local_chilren_indices;
269 }
270
271 template <int dim>
272 types::coarse_cell_id
convert_cell_id_binary_type_to_level_coarse_cell_id(const typename CellId::binary_type & binary_representation)273 convert_cell_id_binary_type_to_level_coarse_cell_id(
274 const typename CellId::binary_type &binary_representation)
275 {
276 // exploiting the structure of CellId::binary_type
277 // see also the documentation of CellId
278
279 // actual coarse-grid id
280 const unsigned int coarse_cell_id = binary_representation[0];
281 const unsigned int n_child_indices = binary_representation[1] >> 2;
282
283 const unsigned int children_per_value =
284 sizeof(CellId::binary_type::value_type) * 8 / dim;
285 unsigned int child_level = 0;
286 unsigned int binary_entry = 2;
287
288 // path to the get to the cell
289 std::vector<unsigned int> cell_indices;
290 while (child_level < n_child_indices)
291 {
292 Assert(binary_entry < binary_representation.size(),
293 ExcInternalError());
294
295 for (unsigned int j = 0; j < children_per_value; ++j)
296 {
297 unsigned int cell_index =
298 (((binary_representation[binary_entry] >> (j * dim))) &
299 (GeometryInfo<dim>::max_children_per_cell - 1));
300 cell_indices.push_back(cell_index);
301 ++child_level;
302 if (child_level == n_child_indices)
303 break;
304 }
305 ++binary_entry;
306 }
307
308 // compute new coarse-grid id: c_{i+1} = c_{i}*2^dim + q;
309 types::coarse_cell_id level_coarse_cell_id = coarse_cell_id;
310 for (auto i : cell_indices)
311 level_coarse_cell_id =
312 level_coarse_cell_id * GeometryInfo<dim>::max_children_per_cell + i;
313
314 return level_coarse_cell_id;
315 }
316
317 } // namespace
318
319 class FineDoFHandlerViewCell
320 {
321 public:
FineDoFHandlerViewCell(const std::function<bool ()> & has_children_function,const std::function<void (std::vector<types::global_dof_index> &)> & get_dof_indices_function)322 FineDoFHandlerViewCell(
323 const std::function<bool()> &has_children_function,
324 const std::function<void(std::vector<types::global_dof_index> &)>
325 &get_dof_indices_function)
326 : has_children_function(has_children_function)
327 , get_dof_indices_function(get_dof_indices_function)
328 {}
329
330 bool
has_children()331 has_children() const
332 {
333 return has_children_function();
334 }
335
336 void
get_dof_indices(std::vector<types::global_dof_index> & dof_indices)337 get_dof_indices(std::vector<types::global_dof_index> &dof_indices) const
338 {
339 get_dof_indices_function(dof_indices);
340 }
341
342
343 private:
344 const std::function<bool()> has_children_function;
345 const std::function<void(std::vector<types::global_dof_index> &)>
346 get_dof_indices_function;
347 };
348
349 template <int dim>
350 class CellIDTranslator
351 {
352 public:
CellIDTranslator(const unsigned int n_coarse_cells,const unsigned int n_global_levels)353 CellIDTranslator(const unsigned int n_coarse_cells,
354 const unsigned int n_global_levels)
355 : n_coarse_cells(n_coarse_cells)
356 , n_global_levels(n_global_levels)
357 {
358 tree_sizes.push_back(0);
359 for (unsigned int i = 0; i < n_global_levels; ++i)
360 tree_sizes.push_back(
361 tree_sizes.back() +
362 Utilities::pow(GeometryInfo<dim>::max_children_per_cell, i) *
363 n_coarse_cells);
364 }
365
366 unsigned int
size()367 size() const
368 {
369 return n_coarse_cells *
370 (Utilities::pow(GeometryInfo<dim>::max_children_per_cell,
371 n_global_levels) -
372 1);
373 }
374
375 template <typename T>
376 unsigned int
translate(const T & cell)377 translate(const T &cell) const
378 {
379 unsigned int id = 0;
380
381 id += convert_cell_id_binary_type_to_level_coarse_cell_id<dim>(
382 cell->id().template to_binary<dim>());
383
384 id += tree_sizes[cell->level()];
385
386 return id;
387 }
388
389 template <typename T>
390 unsigned int
translate(const T & cell,const unsigned int i)391 translate(const T &cell, const unsigned int i) const
392 {
393 return (translate(cell) - tree_sizes[cell->level()]) *
394 GeometryInfo<dim>::max_children_per_cell +
395 i + tree_sizes[cell->level() + 1];
396 }
397
398 CellId
to_cell_id(const unsigned int id)399 to_cell_id(const unsigned int id) const
400 {
401 std::vector<std::uint8_t> child_indices;
402
403 unsigned int id_temp = id;
404
405 unsigned int level = 0;
406
407 for (; level < n_global_levels; ++level)
408 if (id < tree_sizes[level])
409 break;
410 level -= 1;
411
412 id_temp -= tree_sizes[level];
413
414 for (unsigned int l = 0; l < level; ++l)
415 {
416 child_indices.push_back(id_temp %
417 GeometryInfo<dim>::max_children_per_cell);
418 id_temp /= GeometryInfo<dim>::max_children_per_cell;
419 }
420
421 std::reverse(child_indices.begin(), child_indices.end());
422
423 return {id_temp, child_indices}; // TODO
424 }
425
426 private:
427 const unsigned int n_coarse_cells;
428 const unsigned int n_global_levels;
429 std::vector<unsigned int> tree_sizes;
430 };
431
432 template <typename MeshType>
433 class FineDoFHandlerView
434 {
435 public:
FineDoFHandlerView(const MeshType & mesh_fine,const MeshType & mesh_coarse)436 FineDoFHandlerView(const MeshType &mesh_fine, const MeshType &mesh_coarse)
437 : mesh_fine(mesh_fine)
438 , mesh_coarse(mesh_coarse)
439 , communicator(get_mpi_comm(mesh_fine) /*TODO: fix for different comms*/)
440 , cell_id_translator(n_coarse_cells(mesh_fine),
441 n_global_levels(mesh_fine))
442 {
443 AssertDimension(n_coarse_cells(mesh_fine), n_coarse_cells(mesh_coarse));
444 AssertIndexRange(n_global_levels(mesh_coarse),
445 n_global_levels(mesh_fine) + 1);
446 }
447
448 void
449 reinit(const IndexSet &is_dst_locally_owned,
450 const IndexSet &is_dst_remote_input,
451 const IndexSet &is_src_locally_owned,
452 const bool check_if_elements_in_is_dst_remote_exist = false)
453 {
454 #ifndef DEAL_II_WITH_MPI
455 Assert(false, ExcNeedsMPI());
456 (void)is_dst_locally_owned;
457 (void)is_dst_remote_input;
458 (void)is_src_locally_owned;
459 (void)check_if_elements_in_is_dst_remote_exist;
460 #else
461 IndexSet is_dst_remote = is_dst_remote_input;
462
463 if (check_if_elements_in_is_dst_remote_exist)
464 {
465 IndexSet is_dst_remote_potentially_relevant = is_dst_remote;
466 is_dst_remote.clear();
467
468 is_dst_remote_potentially_relevant.subtract_set(is_dst_locally_owned);
469
470 std::vector<unsigned int> owning_ranks_of_ghosts(
471 is_dst_remote_potentially_relevant.n_elements());
472
473 {
474 Utilities::MPI::internal::ComputeIndexOwner::
475 ConsensusAlgorithmsPayload process(
476 is_dst_locally_owned,
477 is_dst_remote_potentially_relevant,
478 communicator,
479 owning_ranks_of_ghosts,
480 false);
481
482 Utilities::MPI::ConsensusAlgorithms::Selector<
483 std::pair<types::global_dof_index, types::global_dof_index>,
484 unsigned int>
485 consensus_algorithm(process, communicator);
486 consensus_algorithm.run();
487 }
488
489 for (unsigned i = 0;
490 i < is_dst_remote_potentially_relevant.n_elements();
491 ++i)
492 if (owning_ranks_of_ghosts[i] != numbers::invalid_unsigned_int)
493 is_dst_remote.add_index(
494 is_dst_remote_potentially_relevant.nth_index_in_set(i));
495 }
496
497 // determine owner of remote cells
498 std::vector<unsigned int> is_dst_remote_owners(
499 is_dst_remote.n_elements());
500
501 Utilities::MPI::internal::ComputeIndexOwner::ConsensusAlgorithmsPayload
502 process(is_dst_locally_owned,
503 is_dst_remote,
504 communicator,
505 is_dst_remote_owners,
506 true);
507
508 Utilities::MPI::ConsensusAlgorithms::Selector<
509 std::pair<types::global_dof_index, types::global_dof_index>,
510 unsigned int>
511 consensus_algorithm(process, communicator);
512 consensus_algorithm.run();
513
514 this->is_dst_locally_owned = is_dst_locally_owned;
515 this->is_dst_remote = is_dst_remote;
516 this->is_src_locally_owned = is_src_locally_owned;
517
518 # if false
519 std::cout << "IS_SRC_LOCALLY_OWNED" << std::endl;
520 for (auto i : is_src_locally_owned)
521 std::cout << cell_id_translator.to_cell_id(i) << std::endl;
522 std::cout << std::endl << std::endl << std::endl;
523
524
525 std::cout << "IS_DST_LOCALLY_OWNED" << std::endl;
526 for (auto i : is_dst_locally_owned)
527 std::cout << cell_id_translator.to_cell_id(i) << std::endl;
528 std::cout << std::endl << std::endl << std::endl;
529 # endif
530
531 const auto &dof_handler_dst = mesh_fine; // TODO: remove
532 const auto &tria_dst = mesh_fine.get_triangulation(); // TODO
533
534 const unsigned int dofs_per_cell =
535 mesh_coarse.get_fe_collection()[0].dofs_per_cell;
536
537 const auto targets_with_indexset = process.get_requesters();
538
539 std::map<unsigned int, std::vector<unsigned int>> indices_to_be_sent;
540 std::vector<MPI_Request> requests;
541 requests.reserve(targets_with_indexset.size());
542
543 {
544 std::vector<types::global_dof_index> indices(dofs_per_cell);
545
546 for (const auto &i : targets_with_indexset)
547 {
548 indices_to_be_sent[i.first] = {};
549 auto &buffer = indices_to_be_sent[i.first];
550
551 for (auto cell_id : i.second)
552 {
553 typename MeshType::cell_iterator cell(
554 *cell_id_translator.to_cell_id(cell_id).to_cell(tria_dst),
555 &dof_handler_dst);
556
557 cell->get_dof_indices(indices);
558 buffer.insert(buffer.end(), indices.begin(), indices.end());
559 }
560
561 requests.resize(requests.size() + 1);
562
563 MPI_Isend(buffer.data(),
564 buffer.size(),
565 MPI_UNSIGNED,
566 i.first,
567 11,
568 communicator,
569 &requests.back());
570 }
571 }
572
573
574 std::vector<unsigned int> ghost_indices;
575
576 // process local cells
577 {
578 std::vector<types::global_dof_index> indices(dofs_per_cell);
579
580 for (const auto id : is_dst_locally_owned)
581 {
582 const auto cell_id = cell_id_translator.to_cell_id(id);
583
584 typename MeshType::cell_iterator cell_(*cell_id.to_cell(tria_dst),
585 &dof_handler_dst);
586
587 cell_->get_dof_indices(indices);
588
589 ghost_indices.insert(ghost_indices.end(),
590 indices.begin(),
591 indices.end());
592 }
593 }
594
595 {
596 std::map<unsigned int, std::vector<unsigned int>> rank_to_ids;
597
598 std::set<unsigned int> ranks;
599
600 for (auto i : is_dst_remote_owners)
601 ranks.insert(i);
602
603 for (auto i : ranks)
604 rank_to_ids[i] = {};
605
606 for (unsigned int i = 0; i < is_dst_remote_owners.size(); ++i)
607 rank_to_ids[is_dst_remote_owners[i]].push_back(
608 is_dst_remote.nth_index_in_set(i));
609
610
611 for (unsigned int i = 0; i < ranks.size(); ++i)
612 {
613 MPI_Status status;
614 MPI_Probe(MPI_ANY_SOURCE, 11, communicator, &status);
615
616 int message_length;
617 MPI_Get_count(&status, MPI_UNSIGNED, &message_length);
618
619 std::vector<unsigned int> buffer(message_length);
620
621 MPI_Recv(buffer.data(),
622 buffer.size(),
623 MPI_UNSIGNED,
624 status.MPI_SOURCE,
625 11,
626 communicator,
627 MPI_STATUS_IGNORE);
628
629 ghost_indices.insert(ghost_indices.end(),
630 buffer.begin(),
631 buffer.end());
632
633 const unsigned int rank = status.MPI_SOURCE;
634
635 const auto ids = rank_to_ids[rank];
636
637 std::vector<types::global_dof_index> indices(dofs_per_cell);
638
639 for (unsigned int i = 0, k = 0; i < ids.size(); ++i)
640 {
641 for (unsigned int j = 0; j < dofs_per_cell; ++j, ++k)
642 indices[j] = buffer[k];
643 map[ids[i]] = indices;
644 }
645 }
646
647 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
648 }
649
650 std::sort(ghost_indices.begin(), ghost_indices.end());
651 ghost_indices.erase(std::unique(ghost_indices.begin(),
652 ghost_indices.end()),
653 ghost_indices.end());
654
655 this->is_extended_locally_owned = dof_handler_dst.locally_owned_dofs();
656
657 this->is_extendende_ghosts = IndexSet(dof_handler_dst.n_dofs());
658 this->is_extendende_ghosts.add_indices(ghost_indices.begin(),
659 ghost_indices.end());
660 this->is_extendende_ghosts.subtract_set(this->is_extended_locally_owned);
661
662 #endif
663 }
664
665 FineDoFHandlerViewCell
get_cell(const typename MeshType::cell_iterator & cell)666 get_cell(const typename MeshType::cell_iterator &cell) const
667 {
668 const auto id = this->cell_id_translator.translate(cell);
669
670 const bool is_cell_locally_owned =
671 this->is_dst_locally_owned.is_element(id);
672 const bool is_cell_remotly_owned = this->is_dst_remote.is_element(id);
673
674 const bool has_cell_any_children = [&]() {
675 for (unsigned int i = 0;
676 i < GeometryInfo<MeshType::dimension>::max_children_per_cell;
677 ++i)
678 {
679 const auto j = this->cell_id_translator.translate(cell, i);
680
681 if (this->is_dst_locally_owned.is_element(j))
682 return true;
683
684 if (this->is_dst_remote.is_element(j))
685 return true;
686 }
687
688 return false;
689 }();
690
691 return FineDoFHandlerViewCell(
692 [has_cell_any_children]() { return has_cell_any_children; },
693 [cell, is_cell_locally_owned, is_cell_remotly_owned, id, this](
694 auto &dof_indices) {
695 if (is_cell_locally_owned)
696 {
697 (typename MeshType::cell_iterator(
698 *cell->id().to_cell(mesh_fine.get_triangulation()),
699 &mesh_fine))
700 ->get_dof_indices(dof_indices);
701 }
702 else if (is_cell_remotly_owned)
703 {
704 dof_indices = map.at(id);
705 }
706 else
707 {
708 AssertThrow(false, ExcNotImplemented()); // should not happen!
709 }
710 });
711 }
712
713 FineDoFHandlerViewCell
get_cell(const typename MeshType::cell_iterator & cell,const unsigned int c)714 get_cell(const typename MeshType::cell_iterator &cell,
715 const unsigned int c) const
716 {
717 const auto id = this->cell_id_translator.translate(cell, c);
718
719 const bool is_cell_locally_owned =
720 this->is_dst_locally_owned.is_element(id);
721 const bool is_cell_remotly_owned = this->is_dst_remote.is_element(id);
722
723 return FineDoFHandlerViewCell(
724 [cell]() {
725 AssertThrow(false, ExcNotImplemented()); // currently we do not need
726 // children of children
727
728 return false;
729 },
730 [cell, is_cell_locally_owned, is_cell_remotly_owned, c, id, this](
731 auto &dof_indices) {
732 if (is_cell_locally_owned)
733 {
734 (typename MeshType::cell_iterator(
735 *cell->id().to_cell(mesh_fine.get_triangulation()),
736 &mesh_fine))
737 ->child(c)
738 ->get_dof_indices(dof_indices);
739 }
740 else if (is_cell_remotly_owned)
741 {
742 dof_indices = map.at(id);
743 }
744 else
745 {
746 AssertThrow(false, ExcNotImplemented()); // should not happen!
747 }
748 });
749 }
750
751 const IndexSet &
locally_owned_dofs()752 locally_owned_dofs() const
753 {
754 return is_extended_locally_owned;
755 }
756
757 const IndexSet &
locally_relevant_dofs()758 locally_relevant_dofs() const
759 {
760 return is_extendende_ghosts;
761 }
762
763 private:
764 const MeshType &mesh_fine;
765 const MeshType &mesh_coarse;
766 const MPI_Comm communicator;
767
768 protected:
769 const CellIDTranslator<MeshType::dimension> cell_id_translator;
770
771 private:
772 IndexSet is_dst_locally_owned;
773 IndexSet is_dst_remote;
774 IndexSet is_src_locally_owned;
775
776
777 IndexSet is_extended_locally_owned;
778 IndexSet is_extendende_ghosts;
779
780 std::map<unsigned int, std::vector<types::global_dof_index>> map;
781
782 static unsigned int
n_coarse_cells(const MeshType & mesh)783 n_coarse_cells(const MeshType &mesh)
784 {
785 types::coarse_cell_id n_coarse_cells = 0;
786
787 for (auto cell : mesh.get_triangulation().active_cell_iterators())
788 if (!cell->is_artificial())
789 n_coarse_cells =
790 std::max(n_coarse_cells, cell->id().get_coarse_cell_id());
791
792 return Utilities::MPI::max(n_coarse_cells, get_mpi_comm(mesh)) + 1;
793 }
794
795 static unsigned int
n_global_levels(const MeshType & mesh)796 n_global_levels(const MeshType &mesh)
797 {
798 return mesh.get_triangulation().n_global_levels();
799 }
800 };
801
802 template <typename MeshType>
803 class GlobalCoarseningFineDoFHandlerView : public FineDoFHandlerView<MeshType>
804 {
805 public:
GlobalCoarseningFineDoFHandlerView(const MeshType & dof_handler_dst,const MeshType & dof_handler_src)806 GlobalCoarseningFineDoFHandlerView(const MeshType &dof_handler_dst,
807 const MeshType &dof_handler_src)
808 : FineDoFHandlerView<MeshType>(dof_handler_dst, dof_handler_src)
809 {
810 // get reference to triangulations
811 const auto &tria_dst = dof_handler_dst.get_triangulation();
812 const auto &tria_src = dof_handler_src.get_triangulation();
813
814 // create index sets
815 IndexSet is_dst_locally_owned(this->cell_id_translator.size());
816 IndexSet is_dst_remote(this->cell_id_translator.size());
817 IndexSet is_src_locally_owned(this->cell_id_translator.size());
818
819 for (auto cell : tria_dst.active_cell_iterators())
820 if (!cell->is_artificial() && cell->is_locally_owned())
821 is_dst_locally_owned.add_index(
822 this->cell_id_translator.translate(cell));
823
824
825 for (auto cell : tria_src.active_cell_iterators())
826 if (!cell->is_artificial() && cell->is_locally_owned())
827 {
828 is_src_locally_owned.add_index(
829 this->cell_id_translator.translate(cell));
830 is_dst_remote.add_index(this->cell_id_translator.translate(cell));
831
832 if (cell->level() + 1u == tria_dst.n_global_levels())
833 continue;
834
835 for (unsigned int i = 0;
836 i < GeometryInfo<MeshType::dimension>::max_children_per_cell;
837 ++i)
838 is_dst_remote.add_index(
839 this->cell_id_translator.translate(cell, i));
840 }
841
842 this->reinit(is_dst_locally_owned,
843 is_dst_remote,
844 is_src_locally_owned,
845 true);
846 }
847 };
848
849 class MGTwoLevelTransferImplementation
850 {
851 public:
852 template <int dim, typename Number, typename MeshType>
853 static void
reinit_geometric_transfer(const MeshType & dof_handler_fine,const MeshType & dof_handler_coarse,const dealii::AffineConstraints<Number> & constraint_fine,const dealii::AffineConstraints<Number> & constraint_coarse,MGTwoLevelTransfer<dim,LinearAlgebra::distributed::Vector<Number>> & transfer)854 reinit_geometric_transfer(
855 const MeshType & dof_handler_fine,
856 const MeshType & dof_handler_coarse,
857 const dealii::AffineConstraints<Number> &constraint_fine,
858 const dealii::AffineConstraints<Number> &constraint_coarse,
859 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>
860 &transfer)
861 {
862 const GlobalCoarseningFineDoFHandlerView<MeshType> view(
863 dof_handler_fine, dof_handler_coarse);
864
865 // copy constrain matrix; TODO: why only for the coarse level?
866 transfer.constraint_coarse.copy_from(constraint_coarse);
867
868 // make sure that no hp is used
869 AssertDimension(dof_handler_coarse.get_fe_collection().size(), 1);
870 AssertDimension(dof_handler_fine.get_fe_collection().size(), 1);
871
872 // extract number of components
873 AssertDimension(dof_handler_fine.get_fe().n_components(),
874 dof_handler_coarse.get_fe().n_components());
875
876 transfer.n_components = dof_handler_fine.get_fe().n_components();
877
878 // create partitioners and vectors for internal purposes
879 {
880 // ... for fine mesh
881 {
882 transfer.partitioner_fine.reset(
883 new Utilities::MPI::Partitioner(view.locally_owned_dofs(),
884 view.locally_relevant_dofs(),
885 get_mpi_comm(dof_handler_fine)));
886 transfer.vec_fine.reinit(transfer.partitioner_fine);
887 }
888
889 // ... coarse mesh (needed since user vector might be const)
890 {
891 IndexSet locally_relevant_dofs;
892 DoFTools::extract_locally_relevant_dofs(dof_handler_coarse,
893 locally_relevant_dofs);
894
895 transfer.partitioner_coarse.reset(new Utilities::MPI::Partitioner(
896 dof_handler_coarse.locally_owned_dofs(),
897 locally_relevant_dofs,
898 get_mpi_comm(dof_handler_coarse)));
899 transfer.vec_coarse.reinit(transfer.partitioner_coarse);
900 }
901 }
902
903 // helper function: to process the fine level cells; function @p fu_non_refined is
904 // performed on cells that are not refined and @fu_refined is performed on
905 // children of cells that are refined
906 const auto process_cells =
907 [&view, &dof_handler_coarse](const auto &fu_non_refined,
908 const auto &fu_refined) {
909 // loop over all active locally-owned cells
910 for (const auto &cell_coarse :
911 dof_handler_coarse.active_cell_iterators())
912 {
913 if (cell_coarse->is_artificial() == true ||
914 cell_coarse->is_locally_owned() == false)
915 continue;
916
917 // get a reference to the equivalent cell on the fine
918 // triangulation
919 const auto cell_coarse_on_fine_mesh = view.get_cell(cell_coarse);
920
921 // check if cell has children
922 if (cell_coarse_on_fine_mesh.has_children())
923 // ... cell has children -> process children
924 for (unsigned int c = 0;
925 c < GeometryInfo<dim>::max_children_per_cell;
926 c++)
927 fu_refined(cell_coarse, view.get_cell(cell_coarse, c), c);
928 else // ... cell has no children -> process cell
929 fu_non_refined(cell_coarse, cell_coarse_on_fine_mesh);
930 }
931 };
932
933 // set up two mg-schesmes
934 // (0) no refinement -> identity
935 // (1) h-refinement
936 transfer.schemes.resize(2);
937
938 // check if FE is the same; TODO: better way?
939 AssertDimension(dof_handler_coarse.get_fe(0).dofs_per_cell,
940 dof_handler_fine.get_fe(0).dofs_per_cell);
941
942 // number of dofs on coarse and fine cells
943 transfer.schemes[0].dofs_per_cell_coarse =
944 transfer.schemes[0].dofs_per_cell_fine =
945 transfer.schemes[1].dofs_per_cell_coarse =
946 dof_handler_coarse.get_fe(0).dofs_per_cell;
947 transfer.schemes[1].dofs_per_cell_fine =
948 dof_handler_coarse.get_fe(0).dofs_per_cell *
949 GeometryInfo<dim>::max_children_per_cell;
950
951 // degree of fe on coarse and fine cell
952 transfer.schemes[0].degree_coarse = transfer.schemes[0].degree_fine =
953 transfer.schemes[1].degree_coarse = dof_handler_coarse.get_fe(0).degree;
954 transfer.schemes[1].degree_fine =
955 dof_handler_coarse.get_fe(0).degree * 2 + 1;
956
957 // continuous or discontinuous
958 transfer.schemes[0].fine_element_is_continuous =
959 transfer.schemes[1].fine_element_is_continuous =
960 dof_handler_fine.get_fe(0).dofs_per_vertex > 0;
961
962 // count coarse cells for each scheme (0, 1)
963 {
964 transfer.schemes[0].n_coarse_cells = 0; // reset
965 transfer.schemes[1].n_coarse_cells = 0;
966
967 // count by looping over all coarse cells
968 process_cells(
969 [&](const auto &, const auto &) {
970 transfer.schemes[0].n_coarse_cells++;
971 },
972 [&](const auto &, const auto &, const auto c) {
973 if (c == 0)
974 transfer.schemes[1].n_coarse_cells++;
975 });
976 }
977
978
979 const auto cell_local_chilren_indices =
980 get_child_offsets<dim>(transfer.schemes[0].dofs_per_cell_coarse,
981 dof_handler_fine.get_fe(0).degree + 1,
982 dof_handler_fine.get_fe(0).degree);
983
984
985 // indices
986 {
987 transfer.schemes[0].level_dof_indices_fine.resize(
988 transfer.schemes[0].dofs_per_cell_fine *
989 transfer.schemes[0].n_coarse_cells);
990 transfer.schemes[0].level_dof_indices_coarse.resize(
991 transfer.schemes[0].dofs_per_cell_coarse *
992 transfer.schemes[0].n_coarse_cells);
993
994 transfer.schemes[1].level_dof_indices_fine.resize(
995 transfer.schemes[1].dofs_per_cell_fine *
996 transfer.schemes[1].n_coarse_cells);
997 transfer.schemes[1].level_dof_indices_coarse.resize(
998 transfer.schemes[1].dofs_per_cell_coarse *
999 transfer.schemes[1].n_coarse_cells);
1000
1001 std::vector<types::global_dof_index> local_dof_indices(
1002 transfer.schemes[0].dofs_per_cell_coarse);
1003
1004 // ---------------------- lexicographic_numbering ----------------------
1005 std::vector<unsigned int> lexicographic_numbering;
1006 {
1007 const Quadrature<1> dummy_quadrature(
1008 std::vector<Point<1>>(1, Point<1>()));
1009 internal::MatrixFreeFunctions::ShapeInfo<Number> shape_info;
1010 shape_info.reinit(dummy_quadrature, dof_handler_fine.get_fe(0), 0);
1011 lexicographic_numbering = shape_info.lexicographic_numbering;
1012 }
1013
1014 // ------------------------------ indices ------------------------------
1015 unsigned int *level_dof_indices_coarse_0 =
1016 &transfer.schemes[0].level_dof_indices_coarse[0];
1017 unsigned int *level_dof_indices_fine_0 =
1018 &transfer.schemes[0].level_dof_indices_fine[0];
1019
1020 unsigned int *level_dof_indices_coarse_1 =
1021 &transfer.schemes[1].level_dof_indices_coarse[0];
1022 unsigned int *level_dof_indices_fine_1 =
1023 &transfer.schemes[1].level_dof_indices_fine[0];
1024
1025 process_cells(
1026 [&](const auto &cell_coarse, const auto &cell_fine) {
1027 // parent
1028 {
1029 cell_coarse->get_dof_indices(local_dof_indices);
1030 for (unsigned int i = 0;
1031 i < transfer.schemes[0].dofs_per_cell_coarse;
1032 i++)
1033 level_dof_indices_coarse_0[i] =
1034 transfer.partitioner_coarse->global_to_local(
1035 local_dof_indices[lexicographic_numbering[i]]);
1036 }
1037
1038 // child
1039 {
1040 cell_fine.get_dof_indices(local_dof_indices);
1041 for (unsigned int i = 0;
1042 i < transfer.schemes[0].dofs_per_cell_coarse;
1043 i++)
1044 level_dof_indices_fine_0[i] =
1045 transfer.partitioner_fine->global_to_local(
1046 local_dof_indices[lexicographic_numbering[i]]);
1047 }
1048
1049 // move pointers
1050 {
1051 level_dof_indices_coarse_0 +=
1052 transfer.schemes[0].dofs_per_cell_coarse;
1053 level_dof_indices_fine_0 +=
1054 transfer.schemes[0].dofs_per_cell_fine;
1055 }
1056 },
1057 [&](const auto &cell_coarse, const auto &cell_fine, const auto c) {
1058 // parent (only once at the beginning)
1059 if (c == 0)
1060 {
1061 cell_coarse->get_dof_indices(local_dof_indices);
1062 for (unsigned int i = 0;
1063 i < transfer.schemes[1].dofs_per_cell_coarse;
1064 i++)
1065 level_dof_indices_coarse_1[i] =
1066 transfer.partitioner_coarse->global_to_local(
1067 local_dof_indices[lexicographic_numbering[i]]);
1068 }
1069
1070 // child
1071 {
1072 cell_fine.get_dof_indices(local_dof_indices);
1073 for (unsigned int i = 0;
1074 i < transfer.schemes[1].dofs_per_cell_coarse;
1075 i++)
1076 level_dof_indices_fine_1[cell_local_chilren_indices[c][i]] =
1077 transfer.partitioner_fine->global_to_local(
1078 local_dof_indices[lexicographic_numbering[i]]);
1079 }
1080
1081 // move pointers (only once at the end)
1082 if (c + 1 == GeometryInfo<dim>::max_children_per_cell)
1083 {
1084 level_dof_indices_coarse_1 +=
1085 transfer.schemes[1].dofs_per_cell_coarse;
1086 level_dof_indices_fine_1 +=
1087 transfer.schemes[1].dofs_per_cell_fine;
1088 }
1089 });
1090 }
1091
1092 // ------------- prolongation matrix (0) -> identity matrix --------------
1093 {
1094 AssertDimension(dof_handler_fine.get_fe(0).n_base_elements(), 1);
1095 std::string fe_name =
1096 dof_handler_fine.get_fe(0).base_element(0).get_name();
1097 {
1098 const std::size_t template_starts = fe_name.find_first_of('<');
1099 Assert(fe_name[template_starts + 1] ==
1100 (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1101 ExcInternalError());
1102 fe_name[template_starts + 1] = '1';
1103 }
1104 const std::unique_ptr<FiniteElement<1>> fe(
1105 FETools::get_fe_by_name<1, 1>(fe_name));
1106
1107 transfer.schemes[0].prolongation_matrix_1d.resize(fe->dofs_per_cell *
1108 fe->dofs_per_cell);
1109
1110 for (unsigned int i = 0; i < fe->dofs_per_cell; i++)
1111 transfer.schemes[0]
1112 .prolongation_matrix_1d[i + i * fe->dofs_per_cell] = Number(1.0);
1113 }
1114
1115 // ----------------------- prolongation matrix (1) -----------------------
1116 {
1117 AssertDimension(dof_handler_fine.get_fe(0).n_base_elements(), 1);
1118 std::string fe_name =
1119 dof_handler_fine.get_fe(0).base_element(0).get_name();
1120 {
1121 const std::size_t template_starts = fe_name.find_first_of('<');
1122 Assert(fe_name[template_starts + 1] ==
1123 (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1124 ExcInternalError());
1125 fe_name[template_starts + 1] = '1';
1126 }
1127 const std::unique_ptr<FiniteElement<1>> fe(
1128 FETools::get_fe_by_name<1, 1>(fe_name));
1129
1130 std::vector<unsigned int> renumbering(fe->dofs_per_cell);
1131 {
1132 AssertIndexRange(fe->dofs_per_vertex, 2);
1133 renumbering[0] = 0;
1134 for (unsigned int i = 0; i < fe->dofs_per_line; ++i)
1135 renumbering[i + fe->dofs_per_vertex] =
1136 GeometryInfo<1>::vertices_per_cell * fe->dofs_per_vertex + i;
1137 if (fe->dofs_per_vertex > 0)
1138 renumbering[fe->dofs_per_cell - fe->dofs_per_vertex] =
1139 fe->dofs_per_vertex;
1140 }
1141
1142 // TODO: data structures are saved in form of DG data structures here
1143 const unsigned int shift = fe->dofs_per_cell;
1144 const unsigned int n_child_dofs_1d = fe->dofs_per_cell * 2;
1145
1146 transfer.schemes[1].prolongation_matrix_1d.resize(fe->dofs_per_cell *
1147 n_child_dofs_1d);
1148
1149 for (unsigned int c = 0; c < GeometryInfo<1>::max_children_per_cell;
1150 ++c)
1151 for (unsigned int i = 0; i < fe->dofs_per_cell; ++i)
1152 for (unsigned int j = 0; j < fe->dofs_per_cell; ++j)
1153 transfer.schemes[1]
1154 .prolongation_matrix_1d[i * n_child_dofs_1d + j + c * shift] =
1155 fe->get_prolongation_matrix(c)(renumbering[j], renumbering[i]);
1156 }
1157
1158
1159 // ------------------------------- weights -------------------------------
1160 if (transfer.schemes[0].fine_element_is_continuous)
1161 {
1162 LinearAlgebra::distributed::Vector<Number> touch_count, touch_count_;
1163
1164 touch_count.reinit(transfer.partitioner_fine);
1165
1166 IndexSet locally_relevant_dofs;
1167 DoFTools::extract_locally_relevant_dofs(dof_handler_fine,
1168 locally_relevant_dofs);
1169
1170 const auto partitioner_fine_ =
1171 std::make_shared<Utilities::MPI::Partitioner>(
1172 dof_handler_fine.locally_owned_dofs(),
1173 locally_relevant_dofs,
1174 get_mpi_comm(dof_handler_fine));
1175 transfer.vec_fine.reinit(transfer.partitioner_fine);
1176
1177 touch_count_.reinit(partitioner_fine_);
1178
1179 std::vector<types::global_dof_index> local_dof_indices(
1180 transfer.schemes[0].dofs_per_cell_coarse);
1181
1182 for (auto cell : dof_handler_fine.active_cell_iterators())
1183 {
1184 if (cell->is_locally_owned() == false)
1185 continue;
1186
1187 cell->get_dof_indices(local_dof_indices);
1188
1189 for (auto i : local_dof_indices)
1190 if (constraint_fine.is_constrained(i) == false)
1191 touch_count_[i] += 1;
1192 }
1193
1194 touch_count_.compress(VectorOperation::add);
1195
1196 for (unsigned int i = 0; i < touch_count_.local_size(); ++i)
1197 touch_count_.local_element(i) =
1198 constraint_fine.is_constrained(
1199 touch_count_.get_partitioner()->local_to_global(i)) ?
1200 Number(0.) :
1201 Number(1.) / touch_count_.local_element(i);
1202
1203 // TODO: needed?
1204 touch_count_.update_ghost_values();
1205
1206
1207 // copy weights to other indexset
1208 touch_count.copy_locally_owned_data_from(touch_count_);
1209 touch_count.update_ghost_values();
1210
1211 transfer.schemes[0].weights.resize(
1212 transfer.schemes[0].n_coarse_cells *
1213 transfer.schemes[0].dofs_per_cell_fine);
1214 transfer.schemes[1].weights.resize(
1215 transfer.schemes[1].n_coarse_cells *
1216 transfer.schemes[1].dofs_per_cell_fine);
1217
1218 Number * weights_0 = &transfer.schemes[0].weights[0];
1219 Number * weights_1 = &transfer.schemes[1].weights[0];
1220 unsigned int *dof_indices_fine_0 =
1221 &transfer.schemes[0].level_dof_indices_fine[0];
1222 unsigned int *dof_indices_fine_1 =
1223 &transfer.schemes[1].level_dof_indices_fine[0];
1224
1225 process_cells(
1226 [&](const auto &, const auto &) {
1227 for (unsigned int i = 0;
1228 i < transfer.schemes[0].dofs_per_cell_fine;
1229 i++)
1230 weights_0[i] = touch_count.local_element(dof_indices_fine_0[i]);
1231
1232 dof_indices_fine_0 += transfer.schemes[0].dofs_per_cell_fine;
1233 weights_0 += transfer.schemes[0].dofs_per_cell_fine;
1234 },
1235 [&](const auto &, const auto &, const auto c) {
1236 for (unsigned int i = 0;
1237 i < transfer.schemes[1].dofs_per_cell_coarse;
1238 i++)
1239 weights_1[cell_local_chilren_indices[c][i]] =
1240 touch_count.local_element(
1241 dof_indices_fine_1[cell_local_chilren_indices[c][i]]);
1242
1243 // move pointers (only once at the end)
1244 if (c + 1 == GeometryInfo<dim>::max_children_per_cell)
1245 {
1246 dof_indices_fine_1 += transfer.schemes[1].dofs_per_cell_fine;
1247 weights_1 += transfer.schemes[1].dofs_per_cell_fine;
1248 }
1249 });
1250 }
1251 }
1252
1253
1254
1255 template <int dim, typename Number, typename MeshType>
1256 static void
reinit_polynomial_transfer(const MeshType & dof_handler_fine,const MeshType & dof_handler_coarse,const dealii::AffineConstraints<Number> & constraint_fine,const dealii::AffineConstraints<Number> & constraint_coarse,MGTwoLevelTransfer<dim,LinearAlgebra::distributed::Vector<Number>> & transfer)1257 reinit_polynomial_transfer(
1258 const MeshType & dof_handler_fine,
1259 const MeshType & dof_handler_coarse,
1260 const dealii::AffineConstraints<Number> &constraint_fine,
1261 const dealii::AffineConstraints<Number> &constraint_coarse,
1262 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>
1263 &transfer)
1264 {
1265 AssertDimension(dof_handler_fine.get_triangulation().n_active_cells(),
1266 dof_handler_coarse.get_triangulation().n_active_cells());
1267
1268 // extract number of components
1269 AssertDimension(dof_handler_fine.get_fe_collection().n_components(),
1270 dof_handler_coarse.get_fe_collection().n_components());
1271
1272 transfer.n_components =
1273 dof_handler_fine.get_fe_collection().n_components();
1274
1275 const auto process_cells = [&](const auto &fu) {
1276 typename MeshType::active_cell_iterator //
1277 cell_coarse = dof_handler_coarse.begin_active(), //
1278 end_coarse = dof_handler_coarse.end(), //
1279 cell_fine = dof_handler_fine.begin_active();
1280
1281 for (; cell_coarse != end_coarse; cell_coarse++, cell_fine++)
1282 {
1283 if (!cell_coarse->is_locally_owned())
1284 continue;
1285
1286 fu(cell_coarse, cell_fine);
1287 }
1288 };
1289
1290 std::map<std::pair<unsigned int, unsigned int>, unsigned int>
1291 fe_index_pairs;
1292
1293 process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1294 fe_index_pairs.emplace(
1295 std::pair<unsigned int, unsigned int>(cell_coarse->active_fe_index(),
1296 cell_fine->active_fe_index()),
1297 0);
1298 });
1299
1300 unsigned int counter = 0;
1301 for (auto &f : fe_index_pairs)
1302 f.second = counter++;
1303
1304 transfer.schemes.resize(fe_index_pairs.size());
1305
1306 // extract number of coarse cells
1307 {
1308 for (auto &scheme : transfer.schemes)
1309 scheme.n_coarse_cells = 0;
1310 process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1311 transfer
1312 .schemes[fe_index_pairs[std::pair<unsigned int, unsigned int>(
1313 cell_coarse->active_fe_index(), cell_fine->active_fe_index())]]
1314 .n_coarse_cells++;
1315 });
1316 }
1317
1318 for (const auto &fe_index_pair : fe_index_pairs)
1319 {
1320 transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse =
1321 dof_handler_coarse.get_fe(fe_index_pair.first.first).dofs_per_cell;
1322 transfer.schemes[fe_index_pair.second].dofs_per_cell_fine =
1323 dof_handler_fine.get_fe(fe_index_pair.first.second).dofs_per_cell;
1324
1325 transfer.schemes[fe_index_pair.second].degree_coarse =
1326 dof_handler_coarse.get_fe(fe_index_pair.first.first).degree;
1327 transfer.schemes[fe_index_pair.second].degree_fine =
1328 dof_handler_fine.get_fe(fe_index_pair.first.second).degree;
1329
1330 transfer.schemes[fe_index_pair.second].fine_element_is_continuous =
1331 dof_handler_fine.get_fe(fe_index_pair.first.second)
1332 .dofs_per_vertex > 0;
1333 }
1334
1335 transfer.constraint_coarse.copy_from(constraint_coarse);
1336
1337 const auto comm = get_mpi_comm(dof_handler_coarse);
1338 {
1339 IndexSet locally_relevant_dofs;
1340 DoFTools::extract_locally_relevant_dofs(dof_handler_fine,
1341 locally_relevant_dofs);
1342
1343 transfer.partitioner_fine.reset(new Utilities::MPI::Partitioner(
1344 dof_handler_fine.locally_owned_dofs(), locally_relevant_dofs, comm));
1345 transfer.vec_fine.reinit(transfer.partitioner_fine);
1346 }
1347 {
1348 IndexSet locally_relevant_dofs;
1349 DoFTools::extract_locally_relevant_dofs(dof_handler_coarse,
1350 locally_relevant_dofs);
1351
1352 transfer.partitioner_coarse.reset(new Utilities::MPI::Partitioner(
1353 dof_handler_coarse.locally_owned_dofs(),
1354 locally_relevant_dofs,
1355 comm));
1356 transfer.vec_coarse.reinit(transfer.partitioner_coarse);
1357 }
1358
1359 {
1360 std::vector<std::vector<unsigned int>> lexicographic_numbering_fine(
1361 fe_index_pairs.size());
1362 std::vector<std::vector<unsigned int>> lexicographic_numbering_coarse(
1363 fe_index_pairs.size());
1364 std::vector<std::vector<types::global_dof_index>>
1365 local_dof_indices_coarse(fe_index_pairs.size());
1366 std::vector<std::vector<types::global_dof_index>>
1367 local_dof_indices_fine(fe_index_pairs.size());
1368
1369 for (const auto &fe_index_pair : fe_index_pairs)
1370 {
1371 local_dof_indices_coarse[fe_index_pair.second].resize(
1372 transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse);
1373 local_dof_indices_fine[fe_index_pair.second].resize(
1374 transfer.schemes[fe_index_pair.second].dofs_per_cell_fine);
1375
1376 transfer.schemes[fe_index_pair.second]
1377 .level_dof_indices_fine.resize(
1378 transfer.schemes[fe_index_pair.second].dofs_per_cell_fine *
1379 transfer.schemes[fe_index_pair.second].n_coarse_cells);
1380 transfer.schemes[fe_index_pair.second]
1381 .level_dof_indices_coarse.resize(
1382 transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse *
1383 transfer.schemes[fe_index_pair.second].n_coarse_cells);
1384
1385
1386 // ------------------- lexicographic_numbering --------------------
1387 {
1388 const Quadrature<1> dummy_quadrature(
1389 std::vector<Point<1>>(1, Point<1>()));
1390 internal::MatrixFreeFunctions::ShapeInfo<Number> shape_info;
1391 shape_info.reinit(dummy_quadrature,
1392 dof_handler_fine.get_fe(
1393 fe_index_pair.first.second),
1394 0);
1395 lexicographic_numbering_fine[fe_index_pair.second] =
1396 shape_info.lexicographic_numbering;
1397
1398 shape_info.reinit(dummy_quadrature,
1399 dof_handler_coarse.get_fe(
1400 fe_index_pair.first.first),
1401 0);
1402 lexicographic_numbering_coarse[fe_index_pair.second] =
1403 shape_info.lexicographic_numbering;
1404 }
1405 }
1406
1407 // ------------------------------ indices -----------------------------
1408 std::vector<unsigned int *> level_dof_indices_coarse_(
1409 fe_index_pairs.size());
1410 std::vector<unsigned int *> level_dof_indices_fine_(
1411 fe_index_pairs.size());
1412
1413 for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1414 {
1415 level_dof_indices_coarse_[i] =
1416 &transfer.schemes[i].level_dof_indices_coarse[0];
1417 level_dof_indices_fine_[i] =
1418 &transfer.schemes[i].level_dof_indices_fine[0];
1419 }
1420
1421 process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1422 const auto fe_pair_no =
1423 fe_index_pairs[std::pair<unsigned int, unsigned int>(
1424 cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1425
1426 cell_coarse->get_dof_indices(local_dof_indices_coarse[fe_pair_no]);
1427 for (unsigned int i = 0;
1428 i < transfer.schemes[fe_pair_no].dofs_per_cell_coarse;
1429 i++)
1430 level_dof_indices_coarse_[fe_pair_no][i] =
1431 transfer.partitioner_coarse->global_to_local(
1432 local_dof_indices_coarse
1433 [fe_pair_no][lexicographic_numbering_coarse[fe_pair_no][i]]);
1434
1435
1436 cell_fine->get_dof_indices(local_dof_indices_fine[fe_pair_no]);
1437 for (unsigned int i = 0;
1438 i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1439 i++)
1440 level_dof_indices_fine_[fe_pair_no][i] =
1441 transfer.partitioner_fine->global_to_local(
1442 local_dof_indices_fine
1443 [fe_pair_no][lexicographic_numbering_fine[fe_pair_no][i]]);
1444
1445
1446 level_dof_indices_coarse_[fe_pair_no] +=
1447 transfer.schemes[fe_pair_no].dofs_per_cell_coarse;
1448 level_dof_indices_fine_[fe_pair_no] +=
1449 transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1450 });
1451 }
1452
1453 // ------------------------- prolongation matrix -------------------------
1454 for (auto const &fe_index_pair_ : fe_index_pairs)
1455 {
1456 const auto &fe_index_pair = fe_index_pair_.first;
1457 const auto &fe_index_no = fe_index_pair_.second;
1458
1459 AssertDimension(
1460 dof_handler_fine.get_fe(fe_index_pair.second).n_base_elements(), 1);
1461 std::string fe_name_fine =
1462 dof_handler_fine.get_fe(fe_index_pair.second)
1463 .base_element(0)
1464 .get_name();
1465 {
1466 const std::size_t template_starts = fe_name_fine.find_first_of('<');
1467 Assert(fe_name_fine[template_starts + 1] ==
1468 (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1469 ExcInternalError());
1470 fe_name_fine[template_starts + 1] = '1';
1471 }
1472 const std::unique_ptr<FiniteElement<1>> fe_fine(
1473 FETools::get_fe_by_name<1, 1>(fe_name_fine));
1474
1475 std::vector<unsigned int> renumbering_fine(fe_fine->dofs_per_cell);
1476 {
1477 AssertIndexRange(fe_fine->dofs_per_vertex, 2);
1478 renumbering_fine[0] = 0;
1479 for (unsigned int i = 0; i < fe_fine->dofs_per_line; ++i)
1480 renumbering_fine[i + fe_fine->dofs_per_vertex] =
1481 GeometryInfo<1>::vertices_per_cell * fe_fine->dofs_per_vertex +
1482 i;
1483 if (fe_fine->dofs_per_vertex > 0)
1484 renumbering_fine[fe_fine->dofs_per_cell -
1485 fe_fine->dofs_per_vertex] =
1486 fe_fine->dofs_per_vertex;
1487 }
1488
1489
1490
1491 AssertDimension(
1492 dof_handler_coarse.get_fe(fe_index_pair.first).n_base_elements(),
1493 1);
1494 std::string fe_name_coarse =
1495 dof_handler_coarse.get_fe(fe_index_pair.first)
1496 .base_element(0)
1497 .get_name();
1498 {
1499 const std::size_t template_starts =
1500 fe_name_coarse.find_first_of('<');
1501 Assert(fe_name_coarse[template_starts + 1] ==
1502 (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1503 ExcInternalError());
1504 fe_name_coarse[template_starts + 1] = '1';
1505 }
1506 const std::unique_ptr<FiniteElement<1>> fe_coarse(
1507 FETools::get_fe_by_name<1, 1>(fe_name_coarse));
1508
1509 std::vector<unsigned int> renumbering_coarse(
1510 fe_coarse->dofs_per_cell);
1511 {
1512 AssertIndexRange(fe_coarse->dofs_per_vertex, 2);
1513 renumbering_coarse[0] = 0;
1514 for (unsigned int i = 0; i < fe_coarse->dofs_per_line; ++i)
1515 renumbering_coarse[i + fe_coarse->dofs_per_vertex] =
1516 GeometryInfo<1>::vertices_per_cell *
1517 fe_coarse->dofs_per_vertex +
1518 i;
1519 if (fe_coarse->dofs_per_vertex > 0)
1520 renumbering_coarse[fe_coarse->dofs_per_cell -
1521 fe_coarse->dofs_per_vertex] =
1522 fe_coarse->dofs_per_vertex;
1523 }
1524
1525
1526
1527 FullMatrix<double> matrix(fe_fine->dofs_per_cell,
1528 fe_coarse->dofs_per_cell);
1529 FETools::get_projection_matrix(*fe_coarse, *fe_fine, matrix);
1530 transfer.schemes[fe_index_no].prolongation_matrix_1d.resize(
1531 fe_fine->dofs_per_cell * fe_coarse->dofs_per_cell);
1532
1533 for (unsigned int i = 0, k = 0; i < fe_coarse->dofs_per_cell; ++i)
1534 for (unsigned int j = 0; j < fe_fine->dofs_per_cell; ++j, ++k)
1535 transfer.schemes[fe_index_no].prolongation_matrix_1d[k] =
1536 matrix(renumbering_fine[j], renumbering_coarse[i]);
1537 }
1538
1539 // ------------------------------- weights -------------------------------
1540 const bool fine_element_is_continuous = Utilities::MPI::max(
1541 static_cast<unsigned int>(
1542 transfer.schemes.size() > 0 ?
1543 transfer.schemes.front().fine_element_is_continuous :
1544 false),
1545 comm);
1546 if (fine_element_is_continuous)
1547 {
1548 for (auto &scheme : transfer.schemes)
1549 scheme.weights.resize(scheme.n_coarse_cells *
1550 scheme.dofs_per_cell_fine);
1551
1552 LinearAlgebra::distributed::Vector<Number> touch_count;
1553 touch_count.reinit(transfer.partitioner_fine);
1554
1555 std::vector<unsigned int *> level_dof_indices_fine_(
1556 fe_index_pairs.size());
1557 std::vector<Number *> weights_(fe_index_pairs.size());
1558
1559 for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1560 level_dof_indices_fine_[i] =
1561 &transfer.schemes[i].level_dof_indices_fine[0];
1562
1563 process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1564 const auto fe_pair_no =
1565 fe_index_pairs[std::pair<unsigned int, unsigned int>(
1566 cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1567
1568 for (unsigned int i = 0;
1569 i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1570 i++)
1571 if (constraint_fine.is_constrained(
1572 transfer.partitioner_fine->local_to_global(
1573 level_dof_indices_fine_[fe_pair_no][i])) == false)
1574 touch_count.local_element(
1575 level_dof_indices_fine_[fe_pair_no][i]) += 1;
1576
1577 level_dof_indices_fine_[fe_pair_no] +=
1578 transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1579 });
1580
1581 touch_count.compress(VectorOperation::add);
1582 touch_count.update_ghost_values();
1583
1584 for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1585 {
1586 level_dof_indices_fine_[i] =
1587 &transfer.schemes[i].level_dof_indices_fine[0];
1588 weights_[i] = &transfer.schemes[i].weights[0];
1589 }
1590
1591 process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1592 const auto fe_pair_no =
1593 fe_index_pairs[std::pair<unsigned int, unsigned int>(
1594 cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1595
1596 for (unsigned int i = 0;
1597 i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1598 i++)
1599 if (constraint_fine.is_constrained(
1600 transfer.partitioner_fine->local_to_global(
1601 level_dof_indices_fine_[fe_pair_no][i])) == true)
1602 weights_[fe_pair_no][i] = Number(0.);
1603 else
1604 weights_[fe_pair_no][i] =
1605 Number(1.) / touch_count.local_element(
1606 level_dof_indices_fine_[fe_pair_no][i]);
1607
1608 level_dof_indices_fine_[fe_pair_no] +=
1609 transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1610 weights_[fe_pair_no] +=
1611 transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1612 });
1613 }
1614 }
1615 };
1616
1617 } // namespace internal
1618
1619
1620 template <int dim, typename Number>
1621 void
prolongate(LinearAlgebra::distributed::Vector<Number> & dst,const LinearAlgebra::distributed::Vector<Number> & src)1622 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::prolongate(
1623 LinearAlgebra::distributed::Vector<Number> & dst,
1624 const LinearAlgebra::distributed::Vector<Number> &src) const
1625 {
1626 using VectorizedArrayType = VectorizedArray<Number>;
1627
1628 const unsigned int n_lanes = VectorizedArrayType::size();
1629
1630 this->vec_coarse.copy_locally_owned_data_from(src);
1631 this->vec_coarse.update_ghost_values();
1632 this->constraint_coarse.distribute(this->vec_coarse);
1633 this->vec_coarse
1634 .update_ghost_values(); // note: make sure that ghost values are set
1635
1636 this->vec_fine = Number(0.);
1637
1638 AlignedVector<VectorizedArrayType> evaluation_data_fine;
1639 AlignedVector<VectorizedArrayType> evaluation_data_coarse;
1640
1641 for (const auto &scheme : schemes)
1642 {
1643 // identity -> take short cut and work directly on global vectors
1644 if (scheme.degree_fine == scheme.degree_coarse)
1645 {
1646 const unsigned int *indices_fine =
1647 scheme.level_dof_indices_fine.data();
1648 const unsigned int *indices_coarse =
1649 scheme.level_dof_indices_coarse.data();
1650 const Number *weights = nullptr;
1651
1652 if (scheme.fine_element_is_continuous)
1653 weights = scheme.weights.data();
1654
1655 for (unsigned int cell = 0; cell < scheme.n_coarse_cells; ++cell)
1656 {
1657 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1658 this->vec_fine.local_element(indices_fine[i]) +=
1659 this->vec_coarse.local_element(indices_coarse[i]) *
1660 (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1661
1662 indices_fine += scheme.dofs_per_cell_fine;
1663 indices_coarse += scheme.dofs_per_cell_coarse;
1664
1665 if (scheme.fine_element_is_continuous)
1666 weights += scheme.dofs_per_cell_fine;
1667 }
1668
1669 continue;
1670 }
1671
1672 // general case -> local restriction is needed
1673 evaluation_data_fine.resize(scheme.dofs_per_cell_fine);
1674 evaluation_data_coarse.resize(scheme.dofs_per_cell_fine);
1675
1676 CellTransferFactory cell_transfer(scheme.degree_fine,
1677 scheme.degree_coarse);
1678
1679 const unsigned int n_scalar_dofs_fine =
1680 Utilities::pow(scheme.degree_fine + 1, dim);
1681 const unsigned int n_scalar_dofs_coarse =
1682 Utilities::pow(scheme.degree_coarse + 1, dim);
1683
1684 for (unsigned int cell = 0; cell < scheme.n_coarse_cells; cell += n_lanes)
1685 {
1686 const unsigned int n_lanes_filled =
1687 (cell + n_lanes > scheme.n_coarse_cells) ?
1688 (scheme.n_coarse_cells - cell) :
1689 n_lanes;
1690
1691 // read from source vector
1692 {
1693 const unsigned int *indices =
1694 &scheme
1695 .level_dof_indices_coarse[cell * scheme.dofs_per_cell_coarse];
1696 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1697 {
1698 for (unsigned int i = 0; i < scheme.dofs_per_cell_coarse; ++i)
1699 evaluation_data_coarse[i][v] =
1700 this->vec_coarse.local_element(indices[i]);
1701 indices += scheme.dofs_per_cell_coarse;
1702 }
1703 }
1704
1705 // ---------------------------- coarse -----------------------------
1706 for (int c = n_components - 1; c >= 0; --c)
1707 {
1708 CellProlongator<dim, VectorizedArrayType> cell_prolongator(
1709 scheme.prolongation_matrix_1d,
1710 evaluation_data_coarse.begin() + c * n_scalar_dofs_coarse,
1711 evaluation_data_fine.begin() + c * n_scalar_dofs_fine);
1712
1713 cell_transfer.run(cell_prolongator);
1714 }
1715 // ------------------------------ fine -----------------------------
1716
1717 // weight and write into dst vector
1718 {
1719 const unsigned int *indices =
1720 &scheme.level_dof_indices_fine[cell * scheme.dofs_per_cell_fine];
1721 const Number *weights = nullptr;
1722
1723 if (scheme.fine_element_is_continuous)
1724 weights = &scheme.weights[cell * scheme.dofs_per_cell_fine];
1725
1726 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1727 {
1728 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1729 this->vec_fine.local_element(indices[i]) +=
1730 evaluation_data_fine[i][v] *
1731 (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1732
1733 indices += scheme.dofs_per_cell_fine;
1734
1735 if (scheme.fine_element_is_continuous)
1736 weights += scheme.dofs_per_cell_fine;
1737 }
1738 }
1739 }
1740 }
1741
1742 this->vec_coarse.zero_out_ghosts(); // clear ghost values; else compress in
1743 // do_restrict_add does not work
1744
1745 if (schemes.size() > 0 && schemes.front().fine_element_is_continuous)
1746 this->vec_fine.compress(VectorOperation::add);
1747
1748 dst.copy_locally_owned_data_from(this->vec_fine);
1749 }
1750
1751
1752
1753 template <int dim, typename Number>
1754 void
1755 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
restrict_and_add(LinearAlgebra::distributed::Vector<Number> & dst,const LinearAlgebra::distributed::Vector<Number> & src)1756 restrict_and_add(LinearAlgebra::distributed::Vector<Number> & dst,
1757 const LinearAlgebra::distributed::Vector<Number> &src) const
1758 {
1759 using VectorizedArrayType = VectorizedArray<Number>;
1760
1761 const unsigned int n_lanes = VectorizedArrayType::size();
1762
1763 this->vec_fine.copy_locally_owned_data_from(src);
1764 this->vec_fine.update_ghost_values();
1765
1766 this->vec_coarse.copy_locally_owned_data_from(dst);
1767
1768 AlignedVector<VectorizedArrayType> evaluation_data_fine;
1769 AlignedVector<VectorizedArrayType> evaluation_data_coarse;
1770
1771 for (const auto &scheme : schemes)
1772 {
1773 // identity -> take short cut and work directly on global vectors
1774 if (scheme.degree_fine == scheme.degree_coarse)
1775 {
1776 const unsigned int *indices_fine =
1777 scheme.level_dof_indices_fine.data();
1778 const unsigned int *indices_coarse =
1779 scheme.level_dof_indices_coarse.data();
1780 const Number *weights = nullptr;
1781
1782 if (scheme.fine_element_is_continuous)
1783 weights = scheme.weights.data();
1784
1785 for (unsigned int cell = 0; cell < scheme.n_coarse_cells; ++cell)
1786 {
1787 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1788 constraint_coarse.distribute_local_to_global( // TODO?
1789 partitioner_coarse->local_to_global(indices_coarse[i]),
1790 this->vec_fine.local_element(indices_fine[i]) *
1791 (scheme.fine_element_is_continuous ? weights[i] : 1.0),
1792 this->vec_coarse);
1793
1794 indices_fine += scheme.dofs_per_cell_fine;
1795 indices_coarse += scheme.dofs_per_cell_coarse;
1796
1797 if (scheme.fine_element_is_continuous)
1798 weights += scheme.dofs_per_cell_fine;
1799 }
1800
1801 continue;
1802 }
1803
1804 // general case -> local restriction is needed
1805 evaluation_data_fine.resize(scheme.dofs_per_cell_fine);
1806 evaluation_data_coarse.resize(scheme.dofs_per_cell_fine);
1807
1808 CellTransferFactory cell_transfer(scheme.degree_fine,
1809 scheme.degree_coarse);
1810
1811 const unsigned int n_scalar_dofs_fine =
1812 Utilities::pow(scheme.degree_fine + 1, dim);
1813 const unsigned int n_scalar_dofs_coarse =
1814 Utilities::pow(scheme.degree_coarse + 1, dim);
1815
1816 for (unsigned int cell = 0; cell < scheme.n_coarse_cells; cell += n_lanes)
1817 {
1818 const unsigned int n_lanes_filled =
1819 (cell + n_lanes > scheme.n_coarse_cells) ?
1820 (scheme.n_coarse_cells - cell) :
1821 n_lanes;
1822
1823 // read from source vector and weight
1824 {
1825 const unsigned int *indices =
1826 &scheme.level_dof_indices_fine[cell * scheme.dofs_per_cell_fine];
1827 const Number *weights = nullptr;
1828
1829 if (scheme.fine_element_is_continuous)
1830 weights = &scheme.weights[cell * scheme.dofs_per_cell_fine];
1831
1832 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1833 {
1834 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1835 evaluation_data_fine[i][v] =
1836 this->vec_fine.local_element(indices[i]) *
1837 (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1838
1839 indices += scheme.dofs_per_cell_fine;
1840
1841 if (scheme.fine_element_is_continuous)
1842 weights += scheme.dofs_per_cell_fine;
1843 }
1844 }
1845
1846 // ------------------------------ fine -----------------------------
1847 for (int c = n_components - 1; c >= 0; --c)
1848 {
1849 CellRestrictor<dim, VectorizedArrayType> cell_restrictor(
1850 scheme.prolongation_matrix_1d,
1851 evaluation_data_fine.begin() + c * n_scalar_dofs_fine,
1852 evaluation_data_coarse.begin() + c * n_scalar_dofs_coarse);
1853
1854 cell_transfer.run(cell_restrictor);
1855 }
1856 // ----------------------------- coarse ----------------------------
1857
1858
1859 // write into dst vector
1860 {
1861 const unsigned int *indices =
1862 &scheme
1863 .level_dof_indices_coarse[cell * scheme.dofs_per_cell_coarse];
1864 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1865 {
1866 for (unsigned int i = 0; i < scheme.dofs_per_cell_coarse; ++i)
1867 constraint_coarse.distribute_local_to_global(
1868 partitioner_coarse->local_to_global(indices[i]),
1869 evaluation_data_coarse[i][v],
1870 this->vec_coarse);
1871 indices += scheme.dofs_per_cell_coarse;
1872 }
1873 }
1874 }
1875 }
1876
1877 if (schemes.size() && schemes.front().fine_element_is_continuous)
1878 this->vec_coarse.compress(VectorOperation::add);
1879
1880 dst.copy_locally_owned_data_from(this->vec_coarse);
1881 }
1882
1883
1884
1885 template <int dim, typename Number>
1886 void
1887 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
reinit_geometric_transfer(const DoFHandler<dim> & dof_handler_fine,const DoFHandler<dim> & dof_handler_coarse,const AffineConstraints<Number> & constraint_fine,const AffineConstraints<Number> & constraint_coarse)1888 reinit_geometric_transfer(const DoFHandler<dim> & dof_handler_fine,
1889 const DoFHandler<dim> & dof_handler_coarse,
1890 const AffineConstraints<Number> &constraint_fine,
1891 const AffineConstraints<Number> &constraint_coarse)
1892 {
1893 internal::MGTwoLevelTransferImplementation::reinit_geometric_transfer(
1894 dof_handler_fine,
1895 dof_handler_coarse,
1896 constraint_fine,
1897 constraint_coarse,
1898 *this);
1899 }
1900
1901
1902
1903 template <int dim, typename Number>
1904 void
1905 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
reinit_polynomial_transfer(const DoFHandler<dim> & dof_handler_fine,const DoFHandler<dim> & dof_handler_coarse,const AffineConstraints<Number> & constraint_fine,const AffineConstraints<Number> & constraint_coarse)1906 reinit_polynomial_transfer(const DoFHandler<dim> &dof_handler_fine,
1907 const DoFHandler<dim> &dof_handler_coarse,
1908 const AffineConstraints<Number> &constraint_fine,
1909 const AffineConstraints<Number> &constraint_coarse)
1910 {
1911 internal::MGTwoLevelTransferImplementation::reinit_polynomial_transfer(
1912 dof_handler_fine,
1913 dof_handler_coarse,
1914 constraint_fine,
1915 constraint_coarse,
1916 *this);
1917 }
1918
1919
1920
1921 template <int dim, typename Number>
1922 bool
1923 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
fast_polynomial_transfer_supported(const unsigned int fe_degree_fine,const unsigned int fe_degree_coarse)1924 fast_polynomial_transfer_supported(const unsigned int fe_degree_fine,
1925 const unsigned int fe_degree_coarse)
1926 {
1927 CellTransferFactory cell_transfer(fe_degree_fine, fe_degree_coarse);
1928 CellProlongatorTest cell_transfer_test;
1929
1930 return cell_transfer.run(cell_transfer_test);
1931 }
1932
1933 DEAL_II_NAMESPACE_CLOSE
1934
1935 #endif
1936