PolyDEAL
 
Loading...
Searching...
No Matches
agglomeration_handler.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) XXXX - YYYY by the polyDEAL authors
5//
6// This file is part of the polyDEAL library.
7//
8// Detailed license information governing the source code
9// can be found in LICENSE.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
14
16
18#include <fe_agglodgp.h>
19
20template <int dim, int spacedim>
22 const GridTools::Cache<dim, spacedim> &cache_tria)
23 : cached_tria(std::make_unique<GridTools::Cache<dim, spacedim>>(
24 cache_tria.get_triangulation(),
25 cache_tria.get_mapping()))
26 , communicator(cache_tria.get_triangulation().get_communicator())
27{
28 Assert(dim == spacedim, ExcNotImplemented("Not available with codim > 0"));
29 Assert(dim == 2 || dim == 3, ExcImpossibleInDim(1));
31 &cached_tria->get_triangulation()) == nullptr),
32 ExcNotImplemented());
33 Assert(cached_tria->get_triangulation().n_active_cells() > 0,
34 ExcMessage(
35 "The triangulation must not be empty upon calling this function."));
36
38 hybrid_mesh = false;
40}
41
42
43
44template <int dim, int spacedim>
47 const AgglomerationContainer &cells)
48{
49 Assert(cells.size() > 0, ExcMessage("No cells to be agglomerated."));
50
51 if (cells.size() == 1)
52 hybrid_mesh = true; // mesh is made also by classical cells
53
54 // First index drives the selection of the master cell. After that, store the
55 // master cell.
56 const types::global_cell_index global_master_idx =
57 cells[0]->global_active_cell_index();
58 const types::global_cell_index master_idx = cells[0]->active_cell_index();
59 master_cells_container.push_back(cells[0]);
60 master_slave_relationships[global_master_idx] = -1;
61
62 const typename DoFHandler<dim>::active_cell_iterator cell_dh =
63 cells[0]->as_dof_handler_iterator(agglo_dh);
64 cell_dh->set_active_fe_index(CellAgglomerationType::master);
65
66 // Store slave cells and save the relationship with the parent
67 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
68 slaves;
69 slaves.reserve(cells.size() - 1);
70 // exclude first cell since it's the master cell
71 for (auto it = ++cells.begin(); it != cells.end(); ++it)
72 {
73 slaves.push_back(*it);
74 master_slave_relationships[(*it)->global_active_cell_index()] =
75 global_master_idx; // mark each slave
76 master_slave_relationships_iterators[(*it)->active_cell_index()] =
77 cells[0];
78
79 const typename DoFHandler<dim>::active_cell_iterator cell =
80 (*it)->as_dof_handler_iterator(agglo_dh);
81 cell->set_active_fe_index(CellAgglomerationType::slave); // slave cell
82
83 // If we have a p::d::T, check that all cells are in the same subdomain.
84 // If serial, just check that the subdomain_id is invalid.
85 Assert(((*it)->subdomain_id() == tria->locally_owned_subdomain() ||
86 tria->locally_owned_subdomain() == numbers::invalid_subdomain_id),
87 ExcInternalError());
88 }
89
90 master_slave_relationships_iterators[master_idx] =
91 cells[0]; // set iterator to master cell
92
93 // Store the slaves of each master
94 master2slaves[master_idx] = slaves;
95 // Save to which polygon this agglomerate correspond
96 master2polygon[master_idx] = n_agglomerations;
97
98 ++n_agglomerations; // an agglomeration has been performed, record it
99
100 create_bounding_box(cells); // fill the vector of bboxes
101
102 // Finally, return a polygonal iterator to the polytope just constructed.
103 return {cells[0], this};
104}
105
106
107
108template <int dim, int spacedim>
109void
111 const AgglomerationContainer &cells)
112{
113 Assert(cells.size() > 0, ExcMessage("No cells to be agglomerated."));
114
115 // Compute the graph associated to the agglomerate
116 Utils::Graph g;
118
119 // The following vector will be filled with connected components
120 std::vector<std::vector<types::global_cell_index>> connected_components;
121 Utils::compute_connected_components(g, connected_components);
122
123 // Be verbose in debug mode
124#ifdef AGGLO_DEBUG
125 if (connected_components.size() > 1)
126 std::cout << "Disconnected elements. Connected components will be "
127 "computed and agglomerated together."
128 << std::endl;
129#endif
130
131 // Get connected components and define one agglomerate for each one of them.
132 std::vector<typename Triangulation<dim>::active_cell_iterator> agglomerate;
133 for (const auto &comp : connected_components)
134 {
135 agglomerate.reserve(comp.size());
136 for (const types::global_cell_index local_idx : comp)
137 agglomerate.push_back(cells[local_idx]);
138
139 // Perform agglomeration
140 define_agglomerate(agglomerate);
141 agglomerate.clear();
142 }
143}
144
145
146template <int dim, int spacedim>
147void
149 const Quadrature<dim> &cell_quadrature,
150 const UpdateFlags &flags,
151 const Quadrature<dim - 1> &face_quadrature,
152 const UpdateFlags &face_flags)
153{
154 agglomeration_quad = cell_quadrature;
155 agglomeration_flags = flags;
156 agglomeration_face_quad = face_quadrature;
157 agglomeration_face_flags = face_flags | internal_agglomeration_face_flags;
158
159
160 no_values =
161 std::make_unique<FEValues<dim>>(*mapping,
162 dummy_fe,
163 agglomeration_quad,
165 update_JxW_values); // only for quadrature
166 no_face_values = std::make_unique<FEFaceValues<dim>>(
167 *mapping,
168 dummy_fe,
169 agglomeration_face_quad,
171 update_normal_vectors); // only for quadrature
172}
173
174
175
176template <int dim, int spacedim>
177unsigned int
180{
181 unsigned int n_neighbors = 0;
182 for (const auto &f : cell->face_indices())
183 {
184 const auto &neighboring_cell = cell->neighbor(f);
185 if ((cell->face(f)->at_boundary()) ||
186 (neighboring_cell->is_active() &&
187 !are_cells_agglomerated(cell, neighboring_cell)))
189 ++n_neighbors;
190 }
191 }
192 return n_neighbors;
193}
194
195
196
197template <int dim, int spacedim>
198void
200 const std::unique_ptr<GridTools::Cache<dim, spacedim>> &cache_tria)
201{
202 tria = &cache_tria->get_triangulation();
203 mapping = &cache_tria->get_mapping();
204
205 agglo_dh.reinit(*tria);
206
207 if (const auto parallel_tria = dynamic_cast<
208 const dealii::parallel::TriangulationBase<dim, spacedim> *>(&*tria))
209 {
210 const std::weak_ptr<const Utilities::MPI::Partitioner> cells_partitioner =
211 parallel_tria->global_active_cell_index_partitioner();
212 master_slave_relationships.reinit(
213 cells_partitioner.lock()->locally_owned_range(), communicator);
214 }
215 else
216 {
217 master_slave_relationships.reinit(tria->n_active_cells(), MPI_COMM_SELF);
218 }
219
220 polytope_cache.clear();
221 bboxes.clear();
222
223 // First, update the pointer
224 cached_tria = std::make_unique<GridTools::Cache<dim, spacedim>>(
225 cache_tria->get_triangulation(), cache_tria->get_mapping());
226
227 connect_to_tria_signals();
228 n_agglomerations = 0;
229}
230
231
232
233template <int dim, int spacedim>
234void
236 const FiniteElement<dim> &fe_space)
237{
238 if (dynamic_cast<const FE_DGQ<dim> *>(&fe_space))
239 fe = std::make_unique<FE_DGQ<dim>>(fe_space.degree);
240 else if (dynamic_cast<const FE_AggloDGP<dim> *>(&fe_space))
241 fe = std::make_unique<FE_AggloDGP<dim>>(fe_space.degree);
242 else if (dynamic_cast<const FE_SimplexDGP<dim> *>(&fe_space))
243 fe = std::make_unique<FE_SimplexDGP<dim>>(fe_space.degree);
244 else
246 false,
247 ExcNotImplemented(
248 "Currently, this interface supports only DGQ and DGP bases."));
249
250 box_mapping = std::make_unique<MappingBox<dim>>(
251 bboxes,
252 master2polygon); // construct bounding box mapping
253
254 if (hybrid_mesh)
256 // the mesh is composed by standard and agglomerate cells. initialize
257 // classes needed for standard cells in order to treat that finite
258 // element space as defined on a standard shape and not on the
259 // BoundingBox.
260 standard_scratch =
261 std::make_unique<ScratchData>(*mapping,
262 *fe,
263 QGauss<dim>(2 * fe_space.degree + 2),
264 internal_agglomeration_flags);
265 }
266
267
268 fe_collection.push_back(*fe); // master
269 fe_collection.push_back(
270 FE_Nothing<dim, spacedim>(fe->reference_cell())); // slave
271
272 initialize_hp_structure();
273
274 // in case the tria is distributed, communicate ghost information with
275 // neighboring ranks
276 const bool needs_ghost_info =
277 dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(&*tria) !=
278 nullptr;
279 if (needs_ghost_info)
280 setup_ghost_polytopes();
281
282 setup_connectivity_of_agglomeration();
283
284 if (needs_ghost_info)
285 exchange_interface_values();
286}
287
288
289
290template <int dim, int spacedim>
291void
293 const AgglomerationContainer &polytope)
294{
295 Assert(n_agglomerations > 0,
296 ExcMessage("No agglomeration has been performed."));
297 Assert(dim > 1, ExcNotImplemented());
298
299 std::vector<Point<spacedim>> pts; // store all the vertices
300 for (const auto &cell : polytope)
301 for (const auto i : cell->vertex_indices())
302 pts.push_back(cell->vertex(i));
303
304 bboxes.emplace_back(pts);
305}
306
307
308
309template <int dim, int spacedim>
310void
312{
313 Assert(master_cells_container.size() > 0,
314 ExcMessage("No agglomeration has been performed."));
315 Assert(
316 agglo_dh.n_dofs() > 0,
317 ExcMessage(
318 "The DoFHandler associated to the agglomeration has not been initialized."
319 "It's likely that you forgot to distribute the DoFs. You may want"
320 "to check if a call to `initialize_hp_structure()` has been done."));
321
322 number_of_agglomerated_faces.resize(master2polygon.size(), 0);
323 for (const auto &cell : master_cells_container)
324 {
327 }
328
330 {
331 // communicate the number of faces
332 recv_n_faces = Utilities::MPI::some_to_some(communicator, local_n_faces);
333
334 // send information about boundaries and neighboring polytopes id
335 recv_bdary_info =
336 Utilities::MPI::some_to_some(communicator, local_bdary_info);
337
338 recv_ghosted_master_id =
339 Utilities::MPI::some_to_some(communicator, local_ghosted_master_id);
340 }
341}
342
343
344
345template <int dim, int spacedim>
346void
348{
349 const unsigned int dofs_per_cell = fe->dofs_per_cell;
350 for (const auto &polytope : polytope_iterators())
351 {
352 if (polytope->is_locally_owned())
353 {
354 const unsigned int n_faces = polytope->n_faces();
355 for (unsigned int f = 0; f < n_faces; ++f)
356 {
357 if (!polytope->at_boundary(f))
358 {
359 const auto &neigh_polytope = polytope->neighbor(f);
360 if (!neigh_polytope->is_locally_owned())
361 {
362 // Neighboring polytope is ghosted.
363
364 // Compute shape functions at the interface
365 const auto &current_fe = reinit(polytope, f);
366
367 std::vector<Point<spacedim>> qpoints_to_send =
368 current_fe.get_quadrature_points();
369
370 const std::vector<double> &jxws_to_send =
371 current_fe.get_JxW_values();
372
373 const std::vector<Tensor<1, spacedim>> &normals_to_send =
374 current_fe.get_normal_vectors();
375
376
377 const types::subdomain_id neigh_rank =
378 neigh_polytope->subdomain_id();
379
380 std::pair<CellId, unsigned int> cell_and_face{
381 polytope->id(), f};
382 // Prepare data to send
383 local_qpoints[neigh_rank].emplace(cell_and_face,
384 qpoints_to_send);
385
386 local_jxws[neigh_rank].emplace(cell_and_face,
387 jxws_to_send);
388
389 local_normals[neigh_rank].emplace(cell_and_face,
390 normals_to_send);
391
392
393 const unsigned int n_qpoints = qpoints_to_send.size();
394
395 // TODO: check `agglomeration_flags` before computing
396 // values and gradients.
397 std::vector<std::vector<double>> values_per_qpoints(
398 dofs_per_cell);
399
400 std::vector<std::vector<Tensor<1, spacedim>>>
401 gradients_per_qpoints(dofs_per_cell);
402
403 for (unsigned int i = 0; i < dofs_per_cell; ++i)
404 {
405 values_per_qpoints[i].resize(n_qpoints);
406 gradients_per_qpoints[i].resize(n_qpoints);
407 for (unsigned int q = 0; q < n_qpoints; ++q)
408 {
409 values_per_qpoints[i][q] =
410 current_fe.shape_value(i, q);
411 gradients_per_qpoints[i][q] =
412 current_fe.shape_grad(i, q);
413 }
414 }
416 local_values[neigh_rank].emplace(cell_and_face,
417 values_per_qpoints);
418 local_gradients[neigh_rank].emplace(
419 cell_and_face, gradients_per_qpoints);
420 }
421 }
422 }
423 }
424 }
425
426 // Finally, exchange with neighboring ranks
427 recv_qpoints = Utilities::MPI::some_to_some(communicator, local_qpoints);
428 recv_jxws = Utilities::MPI::some_to_some(communicator, local_jxws);
429 recv_normals = Utilities::MPI::some_to_some(communicator, local_normals);
430 recv_values = Utilities::MPI::some_to_some(communicator, local_values);
431 recv_gradients = Utilities::MPI::some_to_some(communicator, local_gradients);
432}
433
434
435
436template <int dim, int spacedim>
440 &cells,
442 &master_cell) const
443{
444 Assert(is_master_cell(master_cell),
445 ExcMessage("This must be a master cell."));
446
447 std::vector<Point<dim>> vec_pts;
448 std::vector<double> vec_JxWs;
449 for (const auto &dummy_cell : cells)
450 {
451 no_values->reinit(dummy_cell);
452 auto q_points = no_values->get_quadrature_points(); // real qpoints
453 const auto &JxWs = no_values->get_JxW_values();
454
455 std::transform(q_points.begin(),
456 q_points.end(),
457 std::back_inserter(vec_pts),
458 [&](const Point<spacedim> &p) { return p; });
459 std::transform(JxWs.begin(),
460 JxWs.end(),
461 std::back_inserter(vec_JxWs),
462 [&](const double w) { return w; });
463 }
464
465 // Map back each point in real space by using the map associated to the
466 // bounding box.
467 std::vector<Point<dim>> unit_points(vec_pts.size());
468 const auto &bbox =
469 bboxes[master2polygon.at(master_cell->active_cell_index())];
470 unit_points.reserve(vec_pts.size());
471
472 for (unsigned int i = 0; i < vec_pts.size(); i++)
473 unit_points[i] = bbox.real_to_unit(vec_pts[i]);
474
475 return Quadrature<dim>(unit_points, vec_JxWs);
476}
477
478
479
480template <int dim, int spacedim>
481void
483{
484 Assert(agglo_dh.get_triangulation().n_cells() > 0,
485 ExcMessage(
486 "Triangulation must not be empty upon calling this function."));
487 Assert(n_agglomerations > 0,
488 ExcMessage("No agglomeration has been performed."));
489
490 agglo_dh.distribute_dofs(fe_collection);
491 // euler_mapping = std::make_unique<
492 // MappingFEField<dim, spacedim,
493 // LinearAlgebra::distributed::Vector<double>>>( euler_dh, euler_vector);
494}
495
496
497
498template <int dim, int spacedim>
501 const AgglomerationIterator<dim, spacedim> &polytope) const
502{
503 // Assert(euler_mapping,
504 // ExcMessage("The mapping describing the physical element stemming
505 // from "
506 // "agglomeration has not been set up."));
507
508 const auto &deal_cell = polytope->as_dof_handler_iterator(agglo_dh);
509
510 // First check if the polytope is made just by a single cell. If so, use
511 // classical FEValues
512 // if (polytope->n_background_cells() == 1)
513 // return standard_scratch->reinit(deal_cell);
514
515 const auto &agglo_cells = polytope->get_agglomerate();
516
517 Quadrature<dim> agglo_quad = agglomerated_quadrature(agglo_cells, deal_cell);
518
519 agglomerated_scratch = std::make_unique<ScratchData>(*box_mapping,
520 fe_collection[0],
521 agglo_quad,
522 agglomeration_flags);
523 return agglomerated_scratch->reinit(deal_cell);
524}
525
526
527
528template <int dim, int spacedim>
532 const unsigned int face_index,
534 &agglo_isv_ptr) const
537 reinit_master(cell, face_index, agglo_isv_ptr, *this);
538}
539
540
541
542template <int dim, int spacedim>
546 const unsigned int face_index) const
547{
548 // Assert(euler_mapping,
549 // ExcMessage("The mapping describing the physical element stemming
550 // from "
551 // "agglomeration has not been set up."));
552
553 const auto &deal_cell = polytope->as_dof_handler_iterator(agglo_dh);
554 Assert(is_master_cell(deal_cell), ExcMessage("This should be true."));
555
557 reinit_master(deal_cell, face_index, agglomerated_isv_bdary, *this);
558}
559
560
561
562template <int dim, int spacedim>
563std::pair<const FEValuesBase<dim, spacedim> &,
566 const AgglomerationIterator<dim, spacedim> &polytope_in,
567 const AgglomerationIterator<dim, spacedim> &neigh_polytope,
568 const unsigned int local_in,
569 const unsigned int local_neigh) const
570{
571 // If current and neighboring polytopes are both locally owned, then compute
572 // the jump in the classical way without needing information about ghosted
573 // entities.
574 if (polytope_in->is_locally_owned() && neigh_polytope->is_locally_owned())
575 {
576 const auto &cell_in = polytope_in->as_dof_handler_iterator(agglo_dh);
577 const auto &neigh_cell =
578 neigh_polytope->as_dof_handler_iterator(agglo_dh);
579
580 const auto &fe_in =
582 reinit_master(cell_in, local_in, agglomerated_isv, *this);
583 const auto &fe_out =
585 reinit_master(neigh_cell, local_neigh, agglomerated_isv_neigh, *this);
586 std::pair<const FEValuesBase<dim, spacedim> &,
588 my_p(fe_in, fe_out);
589
590 return my_p;
591 }
592 else
593 {
594 Assert((polytope_in->is_locally_owned() &&
595 !neigh_polytope->is_locally_owned()),
596 ExcInternalError());
598 const auto &cell = polytope_in->as_dof_handler_iterator(agglo_dh);
599 const auto &bbox = bboxes[master2polygon.at(cell->active_cell_index())];
600 // const double bbox_measure = bbox.volume();
601
602 const unsigned int neigh_rank = neigh_polytope->subdomain_id();
603 const CellId &neigh_id = neigh_polytope->id();
605 // Retrieve qpoints,JxWs, normals sent previously from the neighboring
606 // rank.
607 std::vector<Point<spacedim>> &real_qpoints =
608 recv_qpoints.at(neigh_rank).at({neigh_id, local_neigh});
609
610 const auto &JxWs = recv_jxws.at(neigh_rank).at({neigh_id, local_neigh});
611
612 std::vector<Tensor<1, spacedim>> &normals =
613 recv_normals.at(neigh_rank).at({neigh_id, local_neigh});
614
615 // Apply the necessary scalings due to the bbox.
616 std::vector<Point<spacedim>> final_unit_q_points;
617 std::transform(real_qpoints.begin(),
618 real_qpoints.end(),
619 std::back_inserter(final_unit_q_points),
620 [&](const Point<spacedim> &p) {
621 return bbox.real_to_unit(p);
622 });
623
624 // std::vector<double> scale_factors(final_unit_q_points.size());
625 // std::vector<double> scaled_weights(final_unit_q_points.size());
626 // std::vector<Tensor<1, dim>> scaled_normals(final_unit_q_points.size());
627
628 // Since we received normal vectors from a neighbor, we have to swap
629 // the
630 // // sign of the vector in order to have outward normals.
631 // for (unsigned int q = 0; q < final_unit_q_points.size(); ++q)
632 // {
633 // for (unsigned int direction = 0; direction < spacedim; ++direction)
634 // scaled_normals[q][direction] =
635 // normals[q][direction] * (bbox.side_length(direction));
636
637 // scaled_normals[q] *= -1;
638
639 // scaled_weights[q] =
640 // (JxWs[q] * scaled_normals[q].norm()) / bbox_measure;
641 // scaled_normals[q] /= scaled_normals[q].norm();
642 // }
643 for (unsigned int q = 0; q < final_unit_q_points.size(); ++q)
644 normals[q] *= -1;
645
646
648 final_unit_q_points, JxWs, normals);
649
650 agglomerated_isv =
651 std::make_unique<NonMatching::FEImmersedSurfaceValues<spacedim>>(
652 *box_mapping, *fe, surface_quad, agglomeration_face_flags);
653
654
655 agglomerated_isv->reinit(cell);
656
657 std::pair<const FEValuesBase<dim, spacedim> &,
659 my_p(*agglomerated_isv, *agglomerated_isv);
660
661 return my_p;
662 }
663}
664
665
666
667template <int dim, int spacedim>
668template <typename SparsityPatternType, typename Number>
669void
671 SparsityPatternType &dsp,
672 const AffineConstraints<Number> &constraints,
673 const bool keep_constrained_dofs,
674 const types::subdomain_id subdomain_id)
675{
676 Assert(n_agglomerations > 0,
677 ExcMessage("The agglomeration has not been set up correctly."));
678 Assert(dsp.empty(),
679 ExcMessage(
680 "The Sparsity pattern must be empty upon calling this function."));
681
682 const IndexSet &locally_owned_dofs = agglo_dh.locally_owned_dofs();
683 const IndexSet locally_relevant_dofs =
685
686 if constexpr (std::is_same_v<SparsityPatternType, DynamicSparsityPattern>)
687 dsp.reinit(locally_owned_dofs.size(),
688 locally_owned_dofs.size(),
689 locally_relevant_dofs);
690 else if constexpr (std::is_same_v<SparsityPatternType,
692 dsp.reinit(locally_owned_dofs, communicator);
693 else
694 AssertThrow(false, ExcNotImplemented());
695
696 // Create the sparsity pattern corresponding only to volumetric terms. The
697 // fluxes needed by DG methods will be filled later.
699 agglo_dh, dsp, constraints, keep_constrained_dofs, subdomain_id);
700
701
702 const unsigned int dofs_per_cell = agglo_dh.get_fe(0).n_dofs_per_cell();
703 std::vector<types::global_dof_index> current_dof_indices(dofs_per_cell);
704 std::vector<types::global_dof_index> neighbor_dof_indices(dofs_per_cell);
705
706 // Loop over all locally owned polytopes, find the neighbor (also ghosted)
707 // and add fluxes to the sparsity pattern.
708 for (const auto &polytope : polytope_iterators())
709 {
710 if (polytope->is_locally_owned())
711 {
712 const unsigned int n_current_faces = polytope->n_faces();
713 polytope->get_dof_indices(current_dof_indices);
714 for (unsigned int f = 0; f < n_current_faces; ++f)
715 {
716 const auto &neigh_polytope = polytope->neighbor(f);
717 if (neigh_polytope.state() == IteratorState::valid)
718 {
719 neigh_polytope->get_dof_indices(neighbor_dof_indices);
720 constraints.add_entries_local_to_global(current_dof_indices,
721 neighbor_dof_indices,
722 dsp,
723 keep_constrained_dofs,
724 {});
725 }
726 }
727 }
728 }
729
730
731
732 if constexpr (std::is_same_v<SparsityPatternType,
734 dsp.compress();
735}
736
737
738
739template <int dim, int spacedim>
740void
742{
743 [[maybe_unused]] const auto parallel_triangulation =
744 dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(&*tria);
745 Assert(parallel_triangulation != nullptr, ExcInternalError());
746
747 const unsigned int n_dofs_per_cell = fe->dofs_per_cell;
748 std::vector<types::global_dof_index> global_dof_indices(n_dofs_per_cell);
749 for (const auto &polytope : polytope_iterators())
750 if (polytope->is_locally_owned())
751 {
752 const CellId &master_cell_id = polytope->id();
753
754 const auto polytope_dh = polytope->as_dof_handler_iterator(agglo_dh);
755 polytope_dh->get_dof_indices(global_dof_indices);
756
757
758 const auto &agglomerate = polytope->get_agglomerate();
759
760 for (const auto &cell : agglomerate)
761 {
762 // interior, locally owned, cell
763 for (const auto &f : cell->face_indices())
764 {
765 if (!cell->at_boundary(f))
766 {
767 const auto &neighbor = cell->neighbor(f);
768 if (neighbor->is_ghost())
769 {
770 // key of the map: the rank to which send the data
771 const types::subdomain_id neigh_rank =
772 neighbor->subdomain_id();
773
774 // inform the "standard" neighbor about the neighboring
775 // id and its master cell
776 local_cell_ids_neigh_cell[neigh_rank].emplace(
777 cell->id(), master_cell_id);
778
779 // inform the neighboring rank that this master cell
780 // (hence polytope) has the following DoF indices
781 local_ghost_dofs[neigh_rank].emplace(
782 master_cell_id, global_dof_indices);
783
784 // ...same for bounding boxes
785 const auto &bbox = bboxes[polytope->index()];
786 local_ghosted_bbox[neigh_rank].emplace(master_cell_id,
787 bbox);
788 }
789 }
790 }
791 }
792 }
793
794 recv_cell_ids_neigh_cell =
795 Utilities::MPI::some_to_some(communicator, local_cell_ids_neigh_cell);
796
797 // Exchange with neighboring ranks the neighboring bounding boxes
798 recv_ghosted_bbox =
799 Utilities::MPI::some_to_some(communicator, local_ghosted_bbox);
800
801 // Exchange with neighboring ranks the neighboring ghosted DoFs
802 recv_ghost_dofs =
803 Utilities::MPI::some_to_some(communicator, local_ghost_dofs);
804}
805
806
807
808namespace dealii
809{
810 namespace internal
811 {
812 template <int dim, int spacedim>
814 {
815 public:
816 static const FEValuesBase<dim, spacedim> &
819 const unsigned int face_index,
821 &agglo_isv_ptr,
823 {
824 Assert(handler.is_master_cell(cell),
825 ExcMessage("This cell must be a master one."));
826
827 AgglomerationIterator<dim, spacedim> it{cell, &handler};
828 const auto &neigh_polytope = it->neighbor(face_index);
829
830 const CellId polytope_in_id = cell->id();
831
832 // Retrieve the bounding box of the agglomeration
833 const auto &bbox =
834 handler.bboxes[handler.master2polygon.at(cell->active_cell_index())];
835
836 CellId polytope_out_id;
837 if (neigh_polytope.state() == IteratorState::valid)
838 polytope_out_id = neigh_polytope->id();
839 else
840 polytope_out_id = polytope_in_id; // on the boundary. Same id
841
842 const auto &common_face = handler.polytope_cache.interface.at(
843 {polytope_in_id, polytope_out_id});
844
845 std::vector<Point<spacedim>> final_unit_q_points;
846 std::vector<double> final_weights;
847 std::vector<Tensor<1, dim>> final_normals;
848
849 const unsigned int expected_qpoints =
850 common_face.size() * handler.agglomeration_face_quad.size();
851 final_unit_q_points.reserve(expected_qpoints);
852 final_weights.reserve(expected_qpoints);
853 final_normals.reserve(expected_qpoints);
854
855
856 for (const auto &[deal_cell, local_face_idx] : common_face)
857 {
858 handler.no_face_values->reinit(deal_cell, local_face_idx);
859
860 const auto &q_points =
861 handler.no_face_values->get_quadrature_points();
862 const auto &JxWs = handler.no_face_values->get_JxW_values();
863 const auto &normals = handler.no_face_values->get_normal_vectors();
864
865 const unsigned int n_qpoints_agglo = q_points.size();
866
867 for (unsigned int q = 0; q < n_qpoints_agglo; ++q)
868 {
869 final_unit_q_points.push_back(bbox.real_to_unit(q_points[q]));
870 final_weights.push_back(JxWs[q]);
871 final_normals.push_back(normals[q]);
872 }
873 }
874
876 final_unit_q_points, final_weights, final_normals);
877
878 agglo_isv_ptr =
879 std::make_unique<NonMatching::FEImmersedSurfaceValues<spacedim>>(
880 *(handler.box_mapping),
881 *(handler.fe),
882 surface_quad,
884
885 agglo_isv_ptr->reinit(cell);
886
887 return *agglo_isv_ptr;
888 }
889
890
891
898 static void
901 &master_cell,
903 {
904 Assert(
905 handler.master_slave_relationships[master_cell
906 ->global_active_cell_index()] ==
907 -1,
908 ExcMessage("The present cell with index " +
909 std::to_string(master_cell->global_active_cell_index()) +
910 "is not a master one."));
911
912 const auto &agglomeration = handler.get_agglomerate(master_cell);
913 const types::global_cell_index current_polytope_index =
914 handler.master2polygon.at(master_cell->active_cell_index());
915
916 CellId current_polytope_id = master_cell->id();
917
918
919 std::set<types::global_cell_index> visited_polygonal_neighbors;
920
921 std::map<unsigned int, CellId> face_to_neigh_id;
922
923 std::map<unsigned int, bool> is_face_at_boundary;
924
925 // same as above, but with CellId
926 std::set<CellId> visited_polygonal_neighbors_id;
927 unsigned int ghost_counter = 0;
928
929 for (const auto &cell : agglomeration)
930 {
932 cell->active_cell_index();
933
934 const CellId cell_id = cell->id();
935
936 for (const auto f : cell->face_indices())
937 {
938 const auto &neighboring_cell = cell->neighbor(f);
939
940 const bool valid_neighbor =
941 neighboring_cell.state() == IteratorState::valid;
942
943 if (valid_neighbor)
944 {
945 if (neighboring_cell->is_locally_owned() &&
946 !handler.are_cells_agglomerated(cell, neighboring_cell))
947 {
948 // - cell is not on the boundary,
949 // - it's not agglomerated with the neighbor. If so,
950 // it's a neighbor of the present agglomeration
951 // std::cout << " (from rank) "
952 // << Utilities::MPI::this_mpi_process(
953 // handler.communicator)
954 // << std::endl;
955
956 // std::cout
957 // << "neighbor locally owned? " << std::boolalpha
958 // << neighboring_cell->is_locally_owned() <<
959 // std::endl;
960 // if (neighboring_cell->is_ghost())
961 // handler.ghosted_indices.push_back(
962 // neighboring_cell->active_cell_index());
963
964 // a new face of the agglomeration has been
965 // discovered.
966 handler.polygon_boundary[master_cell].push_back(
967 cell->face(f));
968
969 // global index of neighboring deal.II cell
970 const types::global_cell_index neighboring_cell_index =
971 neighboring_cell->active_cell_index();
972
973 // master cell for the neighboring polytope
974 const auto &master_of_neighbor =
976 neighboring_cell_index);
977
978 const auto nof = cell->neighbor_of_neighbor(f);
979
980 if (handler.is_slave_cell(neighboring_cell))
981 {
982 // index of the neighboring polytope
984 neighbor_polytope_index =
985 handler.master2polygon.at(
986 master_of_neighbor->active_cell_index());
987
988 CellId neighbor_polytope_id =
989 master_of_neighbor->id();
990
991 if (visited_polygonal_neighbors.find(
992 neighbor_polytope_index) ==
993 std::end(visited_polygonal_neighbors))
994 {
995 // found a neighbor
996
997 const unsigned int n_face =
999 [current_polytope_index];
1000
1001 handler.polytope_cache.cell_face_at_boundary[{
1002 current_polytope_index, n_face}] = {
1003 false, master_of_neighbor};
1004
1005 is_face_at_boundary[n_face] = true;
1006
1008 [current_polytope_index];
1009
1010 visited_polygonal_neighbors.insert(
1011 neighbor_polytope_index);
1012 }
1013
1014
1015 if (handler.polytope_cache.visited_cell_and_faces
1016 .find({cell_index, f}) ==
1017 std::end(handler.polytope_cache
1018 .visited_cell_and_faces))
1019 {
1020 handler.polytope_cache
1021 .interface[{
1022 current_polytope_id, neighbor_polytope_id}]
1023 .emplace_back(cell, f);
1024
1025 handler.polytope_cache.visited_cell_and_faces
1026 .insert({cell_index, f});
1027 }
1028
1029
1030 if (handler.polytope_cache.visited_cell_and_faces
1031 .find({neighboring_cell_index, nof}) ==
1032 std::end(handler.polytope_cache
1033 .visited_cell_and_faces))
1034 {
1035 handler.polytope_cache
1036 .interface[{
1037 neighbor_polytope_id, current_polytope_id}]
1038 .emplace_back(neighboring_cell, nof);
1039
1040 handler.polytope_cache.visited_cell_and_faces
1041 .insert({neighboring_cell_index, nof});
1042 }
1043 }
1044 else
1045 {
1046 // neighboring cell is a master
1047
1048 // save the pair of neighboring cells
1050 neighbor_polytope_index =
1051 handler.master2polygon.at(
1052 neighboring_cell_index);
1053
1054 CellId neighbor_polytope_id =
1055 neighboring_cell->id();
1056
1057 if (visited_polygonal_neighbors.find(
1058 neighbor_polytope_index) ==
1059 std::end(visited_polygonal_neighbors))
1060 {
1061 // found a neighbor
1062 const unsigned int n_face =
1064 [current_polytope_index];
1065
1066
1067 handler.polytope_cache.cell_face_at_boundary[{
1068 current_polytope_index, n_face}] = {
1069 false, neighboring_cell};
1070
1071 is_face_at_boundary[n_face] = true;
1072
1074 [current_polytope_index];
1075
1076 visited_polygonal_neighbors.insert(
1077 neighbor_polytope_index);
1078 }
1079
1080
1081
1082 if (handler.polytope_cache.visited_cell_and_faces
1083 .find({cell_index, f}) ==
1084 std::end(handler.polytope_cache
1085 .visited_cell_and_faces))
1086 {
1087 handler.polytope_cache
1088 .interface[{
1089 current_polytope_id, neighbor_polytope_id}]
1090 .emplace_back(cell, f);
1091
1092 handler.polytope_cache.visited_cell_and_faces
1093 .insert({cell_index, f});
1094 }
1095
1096 if (handler.polytope_cache.visited_cell_and_faces
1097 .find({neighboring_cell_index, nof}) ==
1098 std::end(handler.polytope_cache
1099 .visited_cell_and_faces))
1100 {
1101 handler.polytope_cache
1102 .interface[{
1103 neighbor_polytope_id, current_polytope_id}]
1104 .emplace_back(neighboring_cell, nof);
1105
1106 handler.polytope_cache.visited_cell_and_faces
1107 .insert({neighboring_cell_index, nof});
1108 }
1109 }
1110 }
1111 else if (neighboring_cell->is_ghost())
1112 {
1113 const auto nof = cell->neighbor_of_neighbor(f);
1114
1115 // from neighboring rank,receive the association
1116 // between standard cell ids and neighboring polytope.
1117 // This tells to the current rank that the
1118 // neighboring cell has the following CellId as master
1119 // cell.
1120 const auto &check_neigh_poly_ids =
1121 handler.recv_cell_ids_neigh_cell.at(
1122 neighboring_cell->subdomain_id());
1123
1124 const CellId neighboring_cell_id =
1125 neighboring_cell->id();
1126
1127 const CellId &check_neigh_polytope_id =
1128 check_neigh_poly_ids.at(neighboring_cell_id);
1129
1130 // const auto master_index =
1131 // master_indices[ghost_counter];
1132
1133 if (visited_polygonal_neighbors_id.find(
1134 check_neigh_polytope_id) ==
1135 std::end(visited_polygonal_neighbors_id))
1136 {
1137 handler.polytope_cache.cell_face_at_boundary[{
1138 current_polytope_index,
1140 [current_polytope_index]}] = {false,
1141 neighboring_cell};
1142
1143
1144 // record the cell id of the neighboring polytope
1145 handler.polytope_cache.ghosted_master_id[{
1146 current_polytope_id,
1148 [current_polytope_index]}] =
1149 check_neigh_polytope_id;
1150
1151
1152 const unsigned int n_face =
1154 [current_polytope_index];
1155
1156 face_to_neigh_id[n_face] = check_neigh_polytope_id;
1157
1158 is_face_at_boundary[n_face] = false;
1159
1160
1161 // increment number of faces
1163 [current_polytope_index];
1164
1165 visited_polygonal_neighbors_id.insert(
1166 check_neigh_polytope_id);
1167
1168 // ghosted polytope has been found, increment
1169 // ghost counter
1170 ++ghost_counter;
1171 }
1172
1173
1174
1175 if (handler.polytope_cache.visited_cell_and_faces_id
1176 .find({cell_id, f}) ==
1177 std::end(
1178 handler.polytope_cache.visited_cell_and_faces_id))
1179 {
1180 handler.polytope_cache
1181 .interface[{
1182 current_polytope_id, check_neigh_polytope_id}]
1183 .emplace_back(cell, f);
1184
1185 // std::cout << "ADDED ("
1186 // << cell->active_cell_index() << ")
1187 // BETWEEN "
1188 // << current_polytope_id << " e "
1189 // << check_neigh_polytope_id <<
1190 // std::endl;
1191
1192 handler.polytope_cache.visited_cell_and_faces_id
1193 .insert({cell_id, f});
1194 }
1195
1196
1197 if (handler.polytope_cache.visited_cell_and_faces_id
1198 .find({neighboring_cell_id, nof}) ==
1199 std::end(
1200 handler.polytope_cache.visited_cell_and_faces_id))
1201 {
1202 handler.polytope_cache
1203 .interface[{
1204 check_neigh_polytope_id, current_polytope_id}]
1205 .emplace_back(neighboring_cell, nof);
1206
1207 handler.polytope_cache.visited_cell_and_faces_id
1208 .insert({neighboring_cell_id, nof});
1209 }
1210 }
1211 }
1212 else if (cell->face(f)->at_boundary())
1213 {
1214 // Boundary face of a boundary cell.
1215 // Note that the neighboring cell must be invalid.
1216
1217 handler.polygon_boundary[master_cell].push_back(
1218 cell->face(f));
1219
1220 if (visited_polygonal_neighbors.find(
1221 std::numeric_limits<unsigned int>::max()) ==
1222 std::end(visited_polygonal_neighbors))
1223 {
1224 // boundary face. Notice that `neighboring_cell` is
1225 // invalid here.
1226 handler.polytope_cache.cell_face_at_boundary[{
1227 current_polytope_index,
1229 [current_polytope_index]}] = {true,
1230 neighboring_cell};
1231
1232 const unsigned int n_face =
1234 [current_polytope_index];
1235
1236 is_face_at_boundary[n_face] = true;
1237
1239 [current_polytope_index];
1240
1241 visited_polygonal_neighbors.insert(
1242 std::numeric_limits<unsigned int>::max());
1243 }
1244
1245
1246
1247 if (handler.polytope_cache.visited_cell_and_faces.find(
1248 {cell_index, f}) ==
1249 std::end(handler.polytope_cache.visited_cell_and_faces))
1250 {
1251 handler.polytope_cache
1252 .interface[{
1253 current_polytope_id, current_polytope_id}]
1254 .emplace_back(cell, f);
1255
1256 handler.polytope_cache.visited_cell_and_faces.insert(
1257 {cell_index, f});
1258 }
1259 }
1260 } // loop over faces
1261 } // loop over all cells of agglomerate
1262
1263
1264
1265 if (ghost_counter > 0)
1266 {
1267 const auto parallel_triangulation = dynamic_cast<
1268 const dealii::parallel::TriangulationBase<dim, spacedim> *>(
1269 &(*handler.tria));
1270
1271 const unsigned int n_faces_current_poly =
1272 handler.number_of_agglomerated_faces[current_polytope_index];
1273
1274 // Communicate to neighboring ranks that current_polytope_id has
1275 // a number of faces equal to n_faces_current_poly faces:
1276 // current_polytope_id -> n_faces_current_poly
1277 for (const unsigned int neigh_rank :
1278 parallel_triangulation->ghost_owners())
1279 {
1280 handler.local_n_faces[neigh_rank].emplace(current_polytope_id,
1281 n_faces_current_poly);
1282
1283 handler.local_bdary_info[neigh_rank].emplace(
1284 current_polytope_id, is_face_at_boundary);
1285
1286 handler.local_ghosted_master_id[neigh_rank].emplace(
1287 current_polytope_id, face_to_neigh_id);
1288 }
1289 }
1290 }
1291 };
1292
1293
1294
1295 } // namespace internal
1296} // namespace dealii
1297
1298
1299
1300template class AgglomerationHandler<1>;
1301template void
1303 DynamicSparsityPattern &sparsity_pattern,
1304 const AffineConstraints<double> &constraints,
1305 const bool keep_constrained_dofs,
1306 const types::subdomain_id subdomain_id);
1307
1308template void
1310 TrilinosWrappers::SparsityPattern &sparsity_pattern,
1311 const AffineConstraints<double> &constraints,
1312 const bool keep_constrained_dofs,
1313 const types::subdomain_id subdomain_id);
1314
1315template class AgglomerationHandler<2>;
1316template void
1318 DynamicSparsityPattern &sparsity_pattern,
1319 const AffineConstraints<double> &constraints,
1320 const bool keep_constrained_dofs,
1321 const types::subdomain_id subdomain_id);
1322
1323template void
1325 TrilinosWrappers::SparsityPattern &sparsity_pattern,
1326 const AffineConstraints<double> &constraints,
1327 const bool keep_constrained_dofs,
1328 const types::subdomain_id subdomain_id);
1329
1330template class AgglomerationHandler<3>;
1331template void
1333 DynamicSparsityPattern &sparsity_pattern,
1334 const AffineConstraints<double> &constraints,
1335 const bool keep_constrained_dofs,
1336 const types::subdomain_id subdomain_id);
1337
1338template void
1340 TrilinosWrappers::SparsityPattern &sparsity_pattern,
1341 const AffineConstraints<double> &constraints,
1342 const bool keep_constrained_dofs,
1343 const types::subdomain_id subdomain_id);
void add_entries_local_to_global(const std::vector< size_type > &local_dof_indices, SparsityPatternBase &sparsity_pattern, const bool keep_constrained_entries=true, const Table< 2, bool > &dof_mask=Table< 2, bool >()) const
const unsigned int degree
size_type size() const
unsigned int size() const
AgglomerationHandler()=default
std::map< types::subdomain_id, std::map< CellId, unsigned int > > local_n_faces
std::unique_ptr< GridTools::Cache< dim, spacedim > > cached_tria
LinearAlgebra::distributed::Vector< float > master_slave_relationships
const FEValues< dim, spacedim > & reinit(const AgglomerationIterator< dim, spacedim > &polytope) const
std::map< types::subdomain_id, std::map< CellId, CellId > > recv_cell_ids_neigh_cell
bool is_slave_cell(const CellIterator &cell) const
std::map< types::subdomain_id, std::map< CellId, std::map< unsigned int, bool > > > local_bdary_info
Quadrature< dim - 1 > agglomeration_face_quad
std::vector< BoundingBox< spacedim > > bboxes
bool are_cells_agglomerated(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell, const typename Triangulation< dim, spacedim >::active_cell_iterator &other_cell) const
Quadrature< dim > agglomerated_quadrature(const AgglomerationContainer &cells, const typename Triangulation< dim, spacedim >::active_cell_iterator &master_cell) const
std::map< const typename Triangulation< dim, spacedim >::active_cell_iterator, std::vector< typename Triangulation< dim >::active_face_iterator > > polygon_boundary
ObserverPointer< const Triangulation< dim, spacedim > > tria
void create_bounding_box(const AgglomerationContainer &polytope)
std::map< types::global_cell_index, types::global_cell_index > master2polygon
typename AgglomerationIterator< dim, spacedim >::AgglomerationContainer AgglomerationContainer
std::pair< const FEValuesBase< dim, spacedim > &, const FEValuesBase< dim, spacedim > & > reinit_interface(const AgglomerationIterator< dim, spacedim > &polytope_in, const AgglomerationIterator< dim, spacedim > &neigh_polytope, const unsigned int local_in, const unsigned int local_outside) const
void create_agglomeration_sparsity_pattern(SparsityPatternType &sparsity_pattern, const AffineConstraints< Number > &constraints=AffineConstraints< Number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
std::map< types::global_cell_index, typename Triangulation< dim, spacedim >::active_cell_iterator > master_slave_relationships_iterators
std::vector< typename Triangulation< dim, spacedim >::active_cell_iterator > get_agglomerate(const typename Triangulation< dim, spacedim >::active_cell_iterator &master_cell) const
unsigned int n_agglomerated_faces_per_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell) const
void distribute_agglomerated_dofs(const FiniteElement< dim > &fe_space)
std::vector< types::global_cell_index > number_of_agglomerated_faces
std::unique_ptr< FEFaceValues< dim, spacedim > > no_face_values
const FEValuesBase< dim, spacedim > & reinit_master(const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, const unsigned int face_number, std::unique_ptr< NonMatching::FEImmersedSurfaceValues< spacedim > > &agglo_isv_ptr) const
bool is_master_cell(const CellIterator &cell) const
void initialize_agglomeration_data(const std::unique_ptr< GridTools::Cache< dim, spacedim > > &cache_tria)
agglomeration_iterator define_agglomerate(const AgglomerationContainer &cells)
void initialize_fe_values(const Quadrature< dim > &cell_quadrature=QGauss< dim >(1), const UpdateFlags &flags=UpdateFlags::update_default, const Quadrature< dim - 1 > &face_quadrature=QGauss< dim - 1 >(1), const UpdateFlags &face_flags=UpdateFlags::update_default)
void define_agglomerate_with_check(const AgglomerationContainer &cells)
std::unique_ptr< MappingBox< dim > > box_mapping
std::unique_ptr< FiniteElement< dim > > fe
internal::PolytopeCache< dim, spacedim > polytope_cache
std::map< types::subdomain_id, std::map< CellId, std::map< unsigned int, CellId > > > local_ghosted_master_id
IteratorState::IteratorStates state() const
static const FEValuesBase< dim, spacedim > & reinit_master(const typename DoFHandler< dim, spacedim >::active_cell_iterator &cell, const unsigned int face_index, std::unique_ptr< NonMatching::FEImmersedSurfaceValues< spacedim > > &agglo_isv_ptr, const AgglomerationHandler< dim, spacedim > &handler)
static void setup_master_neighbor_connectivity(const typename Triangulation< dim, spacedim >::active_cell_iterator &master_cell, const AgglomerationHandler< dim, spacedim > &handler)
unsigned int cell_index
#define Assert(cond, exc)
#define AssertThrow(cond, exc)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
UpdateFlags
update_normal_vectors
update_JxW_values
update_quadrature_points
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
Tensor< 2, dim, Number > w(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
bool job_supports_mpi()
void create_graph_from_agglomerate(const std::vector< typename Triangulation< dim >::active_cell_iterator > &cells, Graph &g)
Definition utils.h:1097
void compute_connected_components(Graph &g, std::vector< std::vector< types::global_cell_index > > &connected_components)
Definition utils.h:1147
const types::subdomain_id invalid_subdomain_id
unsigned int subdomain_id
unsigned int global_cell_index