deal.II version GIT relicensing-6750-g1dc21bc838 2026-09-15 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
agglomeration_poisson.h
Go to the documentation of this file.
1
432 *  
433 * @endcode
434 *
435 * The following headers provide the deal.II functionality needed in this
436 * example. Most of them are standard components for mesh handling, finite
437 * element mappings, linear algebra, and graphical output. In addition, we
438 * include the agglomeration-specific headers that define the data structures
439 * and utilities used to construct and manage polytopal agglomerates.
440 *
441
442 *
443 * deal.II base utilities.
444 *
445 * @code
446 *   #include <deal.II/base/exceptions.h>
447 *  
448 * @endcode
449 *
450 * Finite element mappings.
451 *
452 * @code
453 *   #include <deal.II/fe/mapping_fe.h>
454 *  
455 * @endcode
456 *
457 * Grid generation, mesh input/output, and mesh-related utilities.
458 *
459 * @code
460 *   #include <deal.II/grid/grid_generator.h>
461 *   #include <deal.II/grid/grid_in.h>
462 *   #include <deal.II/grid/grid_out.h>
463 *   #include <deal.II/grid/grid_tools.h>
464 *  
465 * @endcode
466 *
467 * Linear algebra objects and sparse direct solvers.
468 *
469 * @code
470 *   #include <deal.II/lac/precondition.h>
471 *   #include <deal.II/lac/solver_cg.h>
472 *   #include <deal.II/lac/sparse_direct.h>
473 *   #include <deal.II/lac/sparse_matrix.h>
474 *  
475 * @endcode
476 *
477 * Output of finite element data for visualization.
478 *
479 * @code
480 *   #include <deal.II/numerics/data_out.h>
481 *  
482 * @endcode
483 *
484 * Agglomeration-specific headers used in this example.
485 *
486 * @code
487 *   #include <agglomeration_handler.h>
488 *   #include <poly_utils.h>
489 *  
490 * @endcode
491 *
492 * C++ standard library headers.
493 *
494 * @code
495 *   #include <algorithm>
496 *   #include <chrono>
497 *  
498 *  
499 * @endcode
500 *
501 * We use the struct ConvergenceInfo to store the number of degrees of freedom together
502 * with the corresponding L2 and H1 errors, and print a simple
503 * convergence table to the console.
504 *
505 * @code
506 *   struct ConvergenceInfo
507 *   {
508 *   ConvergenceInfo() = default;
509 *   void
510 *   add(const std::pair<types::global_dof_index, std::pair<double, double>>
511 *   &dofs_and_errs)
512 *   {
513 *   vec_data.push_back(dofs_and_errs);
514 *   }
515 *  
516 *   void
517 *   print()
518 *   {
519 *   Assert(vec_data.size() > 0, ExcInternalError());
520 *   std::cout << std::left << "#DoFs, L2 error, H1 error" << std::endl;
521 *  
522 *   for (const auto &dof_and_errs : vec_data)
523 *   std::cout << std::scientific << dof_and_errs.first << ", "
524 *   << dof_and_errs.second.first << ", "
525 *   << dof_and_errs.second.second << std::endl;
526 *   }
527 *  
528 *   std::vector<std::pair<types::global_dof_index, std::pair<double, double>>>
529 *   vec_data;
530 *   };
531 *  
532 * @endcode
533 *
534 * We will compare the performance of three different partitioning strategies:
535 * using METIS, using an R-tree based agglomeration, or not performing any
536 * partitioning at all.
537 *
538 * @code
539 *   enum class PartitionerType
540 *   {
541 *   metis,
542 *   rtree,
543 *   no_partition
544 *   };
545 *  
546 * @endcode
547 *
548 * We then implement the manufactured right-hand side
549 * f(x, y) = 2 π² sin(π x) sin(π y),
550 * which corresponds to the exact solution
551 * u(x, y) = sin(π x) sin(π y).
552 *
553 * @code
554 *   template <int dim>
555 *   class RightHandSide : public Function<dim>
556 *   {
557 *   public:
558 *   RightHandSide()
559 *   : Function<dim>()
560 *   {}
561 *  
562 *   virtual void
563 *   value_list(const std::vector<Point<dim>> &points,
564 *   std::vector<double> &values,
565 *   const unsigned int /*component*/) const override
566 *   {
567 *   for (unsigned int i = 0; i < values.size(); ++i)
568 *   values[i] = 2 * numbers::PI * numbers::PI *
569 *   std::sin(numbers::PI * points[i][0]) *
570 *   std::sin(numbers::PI * points[i][1]);
571 *   }
572 *   };
573 *  
574 *  
575 * @endcode
576 *
577 * Exact solution is set as u(x,y) = sin(pi x) sin(pi y).
578 * It is used to impose Dirichlet boundary conditions and to evaluate
579 * the L2 and H1-seminorm errors. Its gradient is also provided for
580 * the computation of the H1 error.
581 *
582 * @code
583 *   template <int dim>
584 *   class ExactSolution : public Function<dim>
585 *   {
586 *   public:
587 *   ExactSolution()
588 *   : Function<dim>()
589 *   {
590 *   Assert(dim == 2, ExcNotImplemented());
591 *   }
592 *  
593 *   virtual double
594 *   value(const Point<dim> &p,
595 *   const unsigned int /* component */ = 0) const override
596 *   {
597 *   return std::sin(numbers::PI * p[0]) * std::sin(numbers::PI * p[1]);
598 *   }
599 *  
600 *   virtual void
601 *   value_list(const std::vector<Point<dim>> &points,
602 *   std::vector<double> &values,
603 *   const unsigned int /*component*/) const override
604 *   {
605 *   for (unsigned int i = 0; i < values.size(); ++i)
606 *   values[i] = this->value(points[i]);
607 *   }
608 *  
609 *   virtual Tensor<1, dim>
610 *   gradient(const Point<dim> &p,
611 *   const unsigned int /* component */ = 0) const override
612 *   {
613 *   Tensor<1, dim> return_value;
614 *   return_value[0] =
616 *   return_value[1] =
618 *   return return_value;
619 *   }
620 *   };
621 *  
622 * @endcode
623 *
624 * The Poisson<dim> class encapsulates the solution of the model Poisson
625 * problem
626 * @f[ -\Delta u = f \quad \text{in } \Omega, \qquad u = u_D \quad \text{on } \partial\Omega. @f]
627 * It sets up a fine triangulation, constructs agglomerated polytopal
628 * cells according to the chosen partitioning strategy, assembles the
629 * symmetric interior penalty DG discretization on the agglomerated mesh,
630 * solves the resulting linear system, and finally postprocesses the
631 * numerical solution by writing visualization output and computing
632 * global error norms.
633 *
634 * @code
635 *   template <int dim>
636 *   class Poisson
637 *   {
638 *   private:
639 *   void
640 *   make_grid();
641 *   void
642 *   setup_agglomeration();
643 *   void
644 *   assemble_system();
645 *   void
646 *   solve();
647 *   void
648 *   output_results();
649 *  
650 *   Triangulation<dim> tria;
651 *   MappingQ1<dim> mapping;
652 *   FE_DGQ<dim> dg_fe;
653 *   std::unique_ptr<AgglomerationHandler<dim>> ah;
654 *   AffineConstraints<double> constraints;
655 *   SparsityPattern sparsity;
657 *   SparseMatrix<double> system_matrix;
658 *   Vector<double> solution;
659 *   Vector<double> system_rhs;
660 *   std::unique_ptr<GridTools::Cache<dim>> cached_tria;
661 *   std::unique_ptr<const Function<dim>> rhs_function;
662 *   std::unique_ptr<const Function<dim>> analytical_solution;
663 *  
664 *   public:
665 *   Poisson(const PartitionerType &partitioner_type = PartitionerType::rtree,
666 *   const unsigned int = 0,
667 *   const unsigned int = 0,
668 *   const unsigned int fe_degree = 1);
669 *   void
670 *   run();
671 *  
673 *   get_n_dofs() const;
674 *  
675 *   std::pair<double, double>
676 *   get_error() const;
677 *  
678 *   PartitionerType partitioner_type;
679 *   unsigned int extraction_level;
680 *   unsigned int n_subdomains;
681 *   double penalty_constant = 60.; // 10*(p+1)(p+d) for p = 1 and d = 2 => 60
682 *   double l2_err;
683 *   double semih1_err;
684 *   };
685 *  
686 *  
687 * @endcode
688 *
689 * The constructor initializes the Poisson<dim> solver with the selected partitioning
690 * strategy, agglomeration parameters, polynomial degree, and the
691 * manufactured exact solution and right-hand side.
692 *
693 * @code
694 *   template <int dim>
695 *   Poisson<dim>::Poisson(const PartitionerType &partitioner_type,
696 *   const unsigned int extraction_level,
697 *   const unsigned int n_subdomains,
698 *   const unsigned int fe_degree)
699 *   : mapping()
700 *   , dg_fe(fe_degree)
701 *   , partitioner_type(partitioner_type)
702 *   , extraction_level(extraction_level)
703 *   , n_subdomains(n_subdomains)
704 *   , penalty_constant(10. * (fe_degree + 1) * (fe_degree + dim))
705 *   {
706 * @endcode
707 *
708 * Initialize manufactured solution.
709 *
710 * @code
711 *   analytical_solution = std::make_unique<ExactSolution<dim>>();
712 *   rhs_function = std::make_unique<const RightHandSide<dim>>();
713 *   constraints.close();
714 *   }
715 *  
716 *  
717 *  
718 * @endcode
719 *
720 * Build the fine triangulation from a Gmsh mesh, apply a global
721 * refinement, initialize the cache and agglomeration handler, and
722 * define agglomerates according to the selected partitioning strategy.
723 *
724
725 *
726 *
727 * @code
728 *   template <int dim>
729 *   void
730 *   Poisson<dim>::make_grid()
731 *   {
732 *   GridIn<dim> grid_in;
733 *   grid_in.attach_triangulation(tria);
734 *   std::ifstream gmsh_file(std::string(MESH_DIR) +
735 *   "/unit_square_quad_unstructured.msh");
736 *   grid_in.read_msh(gmsh_file);
737 *  
738 *   {
739 *   GridOut grid_out;
740 *   std::ofstream out("grid_input_mesh.vtu");
741 *   grid_out.write_vtu(tria, out); // Write the input mesh (before any refinement), for documentation/figures.
742 *   }
743 *  
744 *   tria.refine_global(5); // Refine the mesh to obtain the fine grid used for agglomeration.
745 *  
746 *   {
747 *   GridOut grid_out;
748 *   std::ofstream out("grid_fine_mesh_refined.vtu");
749 *   grid_out.write_vtu(tria, out); // Write the refined (fine) mesh used as starting point for agglomeration.
750 *   }
751 *  
752 *  
753 *   std::cout << "Size of tria: " << tria.n_active_cells() << std::endl;
754 *   cached_tria = std::make_unique<GridTools::Cache<dim>>(tria, mapping);
755 *   ah = std::make_unique<AgglomerationHandler<dim>>(*cached_tria);
756 *  
757 *   if (partitioner_type == PartitionerType::metis)
758 *   { // Partition the triangulation with a graph partitioner.
759 *   auto start = std::chrono::system_clock::now();
761 *   tria,
763 *  
764 *   std::vector<
765 *   std::vector<typename Triangulation<dim>::active_cell_iterator>>
766 *   cells_per_subdomain(n_subdomains);
767 *   for (const auto &cell : tria.active_cell_iterators())
768 *   cells_per_subdomain[cell->subdomain_id()].push_back(cell);
769 *  
770 *   for (std::size_t i = 0; i < n_subdomains; ++i) // Define one agglomerate for each subdomain
771 *   ah->define_agglomerate(cells_per_subdomain[i]);
772 *  
773 *   std::chrono::duration<double> wctduration =
774 *   (std::chrono::system_clock::now() - start);
775 *   std::cout << "METIS built in " << wctduration.count()
776 *   << " seconds [wall clock]" << std::endl;
777 *   }
778 *   else if (partitioner_type == PartitionerType::rtree)
779 *   { // Build agglomerates from the R-tree hierarchy
780 *  
781 *   namespace bgi = boost::geometry::index;
782 *   static constexpr unsigned int max_elem_per_node =
783 *   PolyUtils::constexpr_pow(2, dim);
784 *   std::vector<std::pair<BoundingBox<dim>,
786 *   boxes(tria.n_active_cells());
787 *   unsigned int i = 0;
788 *   for (const auto &cell : tria.active_cell_iterators())
789 *   boxes[i++] = std::make_pair(mapping.get_bounding_box(cell), cell);
790 *  
791 *   auto start = std::chrono::system_clock::now();
792 *   auto tree = pack_rtree<bgi::rstar<max_elem_per_node>>(boxes);
793 *  
794 *   CellsAgglomerator<dim, decltype(tree)> agglomerator{tree,
795 *   extraction_level};
796 *   const auto vec_agglomerates = agglomerator.extract_agglomerates();
797 *  
798 *   for (const auto &agglo : vec_agglomerates) // Flag elements for agglomeration
799 *   ah->define_agglomerate(agglo);
800 *  
801 *   std::chrono::duration<double> wctduration =
802 *   (std::chrono::system_clock::now() - start);
803 *   std::cout << "R-tree agglomerates built in " << wctduration.count()
804 *   << " seconds [wall clock]" << std::endl;
805 *   }
806 *   else if (partitioner_type == PartitionerType::no_partition)
807 *   {
808 *   }
809 *   else
810 *   {
811 *   Assert(false, ExcMessage("Wrong partitioning."));
812 *   }
813 *   n_subdomains = ah->n_agglomerates();
814 *   std::cout << "N subdomains = " << n_subdomains << std::endl;
815 *   }
816 *  
817 *  
818 * @endcode
819 *
820 * To finalize the agglomeration. In the no-partition case, each fine cell is declared as its own
821 * agglomerate. The function then distributes the degrees of freedom
822 * on the agglomerated mesh, builds the corresponding sparsity pattern,
823 * and writes a VTU file visualizing the agglomeration and the
824 * partitioning of the fine grid.
825 *
826 * @code
827 *   template <int dim>
828 *   void
829 *   Poisson<dim>::setup_agglomeration()
830 *   {
831 *   if (partitioner_type == PartitionerType::no_partition)
832 *   { // No partitioning means that each cell is a master cell
833 *   for (const auto &cell : tria.active_cell_iterators())
834 *   ah->define_agglomerate({cell});
835 *   }
836 *  
837 *   ah->distribute_agglomerated_dofs(dg_fe);
838 *   ah->create_agglomeration_sparsity_pattern(dsp);
839 *   sparsity.copy_from(dsp);
840 *  
841 *   {
842 *   std::string partitioner;
843 *   if (partitioner_type == PartitionerType::metis)
844 *   partitioner = "metis";
845 *   else if (partitioner_type == PartitionerType::rtree)
846 *   partitioner = "rtree";
847 *   else
848 *   partitioner = "no_partitioning";
849 *  
850 *  
851 *   const std::string filename =
852 *   "grid_" + partitioner + "_" + std::to_string(n_subdomains) + ".vtu";
853 *   std::ofstream output(filename);
854 *  
855 *  
856 *   DataOut<dim> data_out;
857 *   data_out.attach_triangulation(tria);
858 *  
859 *   const auto &rel = ah->get_relationships();
860 *  
861 *   Vector<float> agglo_relationships(tria.n_active_cells()); // Store the agglomeration relationships on the fine grid by distinguishing master/slave cells
862 *   for (const auto &cell : tria.active_cell_iterators())
863 *   {
864 *   const unsigned int i = cell->active_cell_index();
865 *   agglo_relationships[i] = rel[i];
866 *   }
867 *  
868 *   Vector<float> agglo_idx(tria.n_active_cells()); // Generate agglo_idx for visualization
869 *  
870 *   for (const auto &polytope : ah->polytope_iterators())
871 *   {
872 *   const float id = static_cast<float>(polytope->index());
873 *   const auto &patch_of_cells = polytope->get_agglomerate();
874 *   for (const auto &cell : patch_of_cells)
875 *   agglo_idx[cell->active_cell_index()] = id;
876 *   }
877 *  
878 *   data_out.add_data_vector(agglo_relationships,
879 *   "agglo_relationships",
881 *   data_out.add_data_vector(agglo_idx,
882 *   "agglo_idx",
884 *  
885 *   data_out.build_patches(mapping);
886 *   data_out.write_vtu(output);
887 *   }
888 *  
889 *  
890 *   }
891 *  
892 * @endcode
893 *
894 * Assemble the global SIPG matrix and right-hand side on the
895 * agglomerated mesh.
896 *
897
898 *
899 * It initializes the system matrix and right-hand side, sets up FEValues
900 * objects on polytopal cells and interfaces, and then adds the volume,
901 * boundary, and interior face contributions of the symmetric interior
902 * penalty formulation.
903 *
904 * @code
905 *   template <int dim>
906 *   void
907 *   Poisson<dim>::assemble_system()
908 *   {
909 *   system_matrix.reinit(sparsity);
910 *   solution.reinit(ah->n_dofs());
911 *   system_rhs.reinit(ah->n_dofs());
912 *  
913 *   const unsigned int quadrature_degree = dg_fe.get_degree() + 1;
914 *   const unsigned int face_quadrature_degree = dg_fe.get_degree() + 1;
915 *  
916 *   ah->initialize_fe_values(QGauss<dim>(quadrature_degree),
920 *   QGauss<dim - 1>(face_quadrature_degree));
921 *  
922 *   const unsigned int dofs_per_cell = ah->n_dofs_per_cell();
923 *   std::cout << "DoFs per cell: " << dofs_per_cell << std::endl;
924 *  
925 *   FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
926 *   Vector<double> cell_rhs(dofs_per_cell);
927 *  
928 * @endcode
929 *
930 * Next, we define the four dofsxdofs matrices needed to assemble jumps and
931 * averages.
932 *
933 * @code
934 *   FullMatrix<double> M11(dofs_per_cell, dofs_per_cell);
935 *   FullMatrix<double> M12(dofs_per_cell, dofs_per_cell);
936 *   FullMatrix<double> M21(dofs_per_cell, dofs_per_cell);
937 *   FullMatrix<double> M22(dofs_per_cell, dofs_per_cell);
938 *  
939 *   std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
940 *  
941 *   for (const auto &polytope : ah->polytope_iterators())
942 *   {
943 *   cell_matrix = 0;
944 *   cell_rhs = 0;
945 *   const auto &agglo_values = ah->reinit(polytope);
946 *   polytope->get_dof_indices(local_dof_indices);
947 *  
948 *   const auto &q_points = agglo_values.get_quadrature_points();
949 *   const unsigned int n_qpoints = q_points.size();
950 *   std::vector<double> rhs(n_qpoints);
951 *   rhs_function->value_list(q_points, rhs);
952 *  
953 *   for (unsigned int q_index : agglo_values.quadrature_point_indices())
954 *   {
955 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
956 *   {
957 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
958 *   {
959 *   cell_matrix(i, j) += agglo_values.shape_grad(i, q_index) *
960 *   agglo_values.shape_grad(j, q_index) *
961 *   agglo_values.JxW(q_index);
962 *   }
963 *   cell_rhs(i) += agglo_values.shape_value(i, q_index) *
964 *   rhs[q_index] * agglo_values.JxW(q_index);
965 *   }
966 *   }
967 *  
968 *  
969 *   const unsigned int n_faces = polytope->n_faces();
970 *   AssertThrow(n_faces > 0,
971 *   ExcMessage(
972 *   "Invalid element: at least 4 faces are required."));
973 *  
974 *   auto polygon_boundary_vertices = polytope->polytope_boundary();
975 *   for (unsigned int f = 0; f < n_faces; ++f)
976 *   {
977 *   if (polytope->at_boundary(f))
978 *   { // std::cout << "at boundary!" << std::endl;
979 *   const auto &fe_face = ah->reinit(polytope, f);
980 *  
981 *   const unsigned int dofs_per_cell = fe_face.dofs_per_cell;
982 *  
983 *   const auto &face_q_points = fe_face.get_quadrature_points();
984 *   std::vector<double> analytical_solution_values(
985 *   face_q_points.size());
986 *   analytical_solution->value_list(face_q_points,
987 *   analytical_solution_values,
988 *   1);
989 *  
990 *   const auto &normals = fe_face.get_normal_vectors(); // Get normal vectors seen from each agglomeration.
991 *  
992 *   const double penalty =
993 *   penalty_constant / std::fabs(polytope->diameter());
994 *  
995 *   for (unsigned int q_index : fe_face.quadrature_point_indices())
996 *   {
997 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
998 *   {
999 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
1000 *   {
1001 *   cell_matrix(i, j) +=
1002 *   (-fe_face.shape_value(i, q_index) *
1003 *   fe_face.shape_grad(j, q_index) *
1004 *   normals[q_index] -
1005 *   fe_face.shape_grad(i, q_index) * normals[q_index] *
1006 *   fe_face.shape_value(j, q_index) +
1007 *   (penalty)*fe_face.shape_value(i, q_index) *
1008 *   fe_face.shape_value(j, q_index)) *
1009 *   fe_face.JxW(q_index);
1010 *   }
1011 *   cell_rhs(i) +=
1012 *   (penalty * analytical_solution_values[q_index] *
1013 *   fe_face.shape_value(i, q_index) -
1014 *   fe_face.shape_grad(i, q_index) * normals[q_index] *
1015 *   analytical_solution_values[q_index]) *
1016 *   fe_face.JxW(q_index);
1017 *   }
1018 *   }
1019 *   }
1020 *   else
1021 *   {
1022 *   const auto &neigh_polytope = polytope->neighbor(f);
1023 *  
1024 *   if (polytope->index() < neigh_polytope->index()) // This is necessary to loop over internal faces only once.
1025 *   {
1026 *   unsigned int nofn =
1027 *   polytope->neighbor_of_agglomerated_neighbor(f);
1028 *  
1029 *   const auto &fe_faces =
1030 *   ah->reinit_interface(polytope, neigh_polytope, f, nofn);
1031 *   const auto &fe_faces0 = fe_faces.first;
1032 *   const auto &fe_faces1 = fe_faces.second;
1033 *  
1034 *   std::vector<types::global_dof_index>
1035 *   local_dof_indices_neighbor(dofs_per_cell);
1036 *  
1037 *   M11 = 0.;
1038 *   M12 = 0.;
1039 *   M21 = 0.;
1040 *   M22 = 0.;
1041 *  
1042 *   const auto &normals = fe_faces0.get_normal_vectors();
1043 *  
1044 *   const double penalty =
1045 *   penalty_constant / std::min(polytope->diameter(), neigh_polytope->diameter());
1046 *  
1047 *  
1048 *   for (unsigned int q_index : // M11
1049 *   fe_faces0.quadrature_point_indices())
1050 *   {
1051 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
1052 *   {
1053 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
1054 *   {
1055 *   M11(i, j) +=
1056 *   (-0.5 * fe_faces0.shape_grad(i, q_index) *
1057 *   normals[q_index] *
1058 *   fe_faces0.shape_value(j, q_index) -
1059 *   0.5 * fe_faces0.shape_grad(j, q_index) *
1060 *   normals[q_index] *
1061 *   fe_faces0.shape_value(i, q_index) +
1062 *   (penalty)*fe_faces0.shape_value(i, q_index) *
1063 *   fe_faces0.shape_value(j, q_index)) *
1064 *   fe_faces0.JxW(q_index);
1065 *  
1066 *   M12(i, j) +=
1067 *   (0.5 * fe_faces0.shape_grad(i, q_index) *
1068 *   normals[q_index] *
1069 *   fe_faces1.shape_value(j, q_index) -
1070 *   0.5 * fe_faces1.shape_grad(j, q_index) *
1071 *   normals[q_index] *
1072 *   fe_faces0.shape_value(i, q_index) -
1073 *   (penalty)*fe_faces0.shape_value(i, q_index) *
1074 *   fe_faces1.shape_value(j, q_index)) *
1075 *   fe_faces1.JxW(q_index);
1076 *  
1077 *  
1078 *   M21(i, j) += // A10
1079 *   (-0.5 * fe_faces1.shape_grad(i, q_index) *
1080 *   normals[q_index] *
1081 *   fe_faces0.shape_value(j, q_index) +
1082 *   0.5 * fe_faces0.shape_grad(j, q_index) *
1083 *   normals[q_index] *
1084 *   fe_faces1.shape_value(i, q_index) -
1085 *   (penalty)*fe_faces1.shape_value(i, q_index) *
1086 *   fe_faces0.shape_value(j, q_index)) *
1087 *   fe_faces1.JxW(q_index);
1088 *  
1089 *  
1090 *   M22(i, j) += // A11
1091 *   (0.5 * fe_faces1.shape_grad(i, q_index) *
1092 *   normals[q_index] *
1093 *   fe_faces1.shape_value(j, q_index) +
1094 *   0.5 * fe_faces1.shape_grad(j, q_index) *
1095 *   normals[q_index] *
1096 *   fe_faces1.shape_value(i, q_index) +
1097 *   (penalty)*fe_faces1.shape_value(i, q_index) *
1098 *   fe_faces1.shape_value(j, q_index)) *
1099 *   fe_faces1.JxW(q_index);
1100 *   }
1101 *   }
1102 *   }
1103 *  
1104 *   neigh_polytope->get_dof_indices(local_dof_indices_neighbor);
1105 *  
1106 *   constraints.distribute_local_to_global(M11,
1107 *   local_dof_indices,
1108 *   system_matrix);
1109 *   constraints.distribute_local_to_global(
1110 *   M12,
1111 *   local_dof_indices,
1112 *   local_dof_indices_neighbor,
1113 *   system_matrix);
1114 *   constraints.distribute_local_to_global(
1115 *   M21,
1116 *   local_dof_indices_neighbor,
1117 *   local_dof_indices,
1118 *   system_matrix);
1119 *   constraints.distribute_local_to_global(
1120 *   M22, local_dof_indices_neighbor, system_matrix);
1121 *   } // Loop only once through internal faces
1122 *   }
1123 *   } // Loop over faces of current cell
1124 *  
1125 * @endcode
1126 *
1127 * Distribute the local contributions to the global system.
1128 *
1129 * @code
1130 *   constraints.distribute_local_to_global(
1131 *   cell_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs);
1132 *   } // Loop over cells
1133 *   }
1134 *  
1135 * @endcode
1136 *
1137 * Solve the linear system by means of a sparse direct solver.
1138 *
1139 * @code
1140 *   template <int dim>
1141 *   void
1142 *   Poisson<dim>::solve()
1143 *   {
1144 *   SparseDirectUMFPACK A_direct;
1145 *   A_direct.initialize(system_matrix);
1146 *   A_direct.vmult(solution, system_rhs);
1147 *   }
1148 *  
1149 *  
1150 * @endcode
1151 *
1152 * Write VTU output and compute the global @f$L^2@f$ and @f$H^1@f$-seminorm
1153 * errors of the agglomerated DG approximation.
1154 *
1155 * @code
1156 *   template <int dim>
1157 *   void
1158 *   Poisson<dim>::output_results()
1159 *   {
1160 *   {
1161 *   std::string partitioner;
1162 *   if (partitioner_type == PartitionerType::metis)
1163 *   partitioner = "metis";
1164 *   else if (partitioner_type == PartitionerType::rtree)
1165 *   partitioner = "rtree";
1166 *   else
1167 *   partitioner = "no_partitioning";
1168 *  
1169 *   const std::string filename = "interpolated_solution_" + partitioner + "_" +
1170 *   std::to_string(n_subdomains) + ".vtu";
1171 *   std::ofstream output(filename);
1172 *  
1173 *   DataOut<dim> data_out;
1174 *   Vector<double> interpolated_solution;
1175 *   PolyUtils::interpolate_to_fine_grid(*ah,
1176 *   interpolated_solution,
1177 *   solution,
1178 *   true /*on_the_fly*/);
1179 *   data_out.attach_dof_handler(ah->output_dh);
1180 *   data_out.add_data_vector(interpolated_solution,
1181 *   "u",
1183 *  
1184 *   Vector<float> agglo_idx(tria.n_active_cells());
1185 *  
1186 * @endcode
1187 *
1188 * Mark fine cells belonging to the same agglomerate.
1189 *
1190 * @code
1191 *   for (const auto &polytope : ah->polytope_iterators())
1192 *   {
1193 *   const types::global_cell_index polytope_index = polytope->index();
1194 *   const auto &patch_of_cells = polytope->get_agglomerate(); // Fine cells
1195 *   for (const auto &cell : patch_of_cells) // Mark all fine cells belonging to the current agglomerate.
1196 *   agglo_idx[cell->active_cell_index()] = polytope_index;
1197 *   }
1198 *  
1199 *   data_out.add_data_vector(agglo_idx,
1200 *   "agglo_idx",
1202 *  
1203 *   data_out.build_patches(mapping);
1204 *   data_out.write_vtu(output);
1205 *  
1206 *   std::vector<double> errors;
1207 *   PolyUtils::compute_global_error(*ah,
1208 *   solution,
1209 *   *analytical_solution,
1212 *   errors); // Compute the global L2 and H1-seminorm errors.
1213 *   l2_err = errors[0];
1214 *   semih1_err = errors[1];
1215 *   }
1216 *   }
1217 *  
1218 *  
1219 * @endcode
1220 *
1221 * Return the number of degrees of freedom on the agglomerated mesh.
1222 *
1223 * @code
1224 *   template <int dim>
1226 *   Poisson<dim>::get_n_dofs() const
1227 *   {
1228 *   return ah->n_dofs();
1229 *   }
1230 *  
1231 *  
1232 * @endcode
1233 *
1234 * Return the pair consisting of the @f$L^2@f$ error and the @f$H^1@f$-seminorm error of the numerical solution.
1235 *
1236 * @code
1237 *   template <int dim>
1238 *   inline std::pair<double, double>
1239 *   Poisson<dim>::get_error() const
1240 *   {
1241 *   return std::make_pair(l2_err, semih1_err);
1242 *   }
1243 *  
1244 *  
1245 * @endcode
1246 *
1247 * Run the full workflow: mesh generation, agglomeration setup,
1248 * assembly, solution, and postprocessing.
1249 *
1250 * @code
1251 *   template <int dim>
1252 *   void
1253 *   Poisson<dim>::run()
1254 *   {
1255 *   make_grid();
1256 *   setup_agglomeration();
1257 *   auto start = std::chrono::high_resolution_clock::now();
1258 *   assemble_system();
1259 *   auto stop = std::chrono::high_resolution_clock::now();
1260 *   auto duration =
1261 *   std::chrono::duration_cast<std::chrono::seconds>(stop - start);
1262 *  
1263 *   std::cout << "Time taken by assemble_system(): " << duration.count()
1264 *   << " seconds" << std::endl;
1265 *   solve();
1266 *   output_results();
1267 *   }
1268 *  
1269 * @endcode
1270 *
1271 * Driver code.
1272 *
1273 * @code
1274 *   int
1275 *   main()
1276 *   {
1277 *   ConvergenceInfo convergence_info;
1278 *  
1279 *   for (unsigned int fe_degree : {1}) //, 2, 3})
1280 *   {
1281 *   std::cout << "Running with FE degree: " << fe_degree << std::endl;
1282 *   Poisson<2> poisson_problem{PartitionerType::rtree, // Three choices: metis, rtree and no_partition
1283 *   4 /* extraction_level */,
1284 *   91 /* n_subdomains */,
1285 *   fe_degree};
1286 *   poisson_problem.run();
1287 *   convergence_info.add(
1288 *   std::make_pair<types::global_dof_index, std::pair<double, double>>(
1289 *   poisson_problem.get_n_dofs(), poisson_problem.get_error()));
1290 *   std::cout << std::endl;
1291 *   }
1292 *  
1293 *   std::cout << "Convergence table:" << std::endl;
1294 *   convergence_info.print();
1295 *   std::cout << std::endl;
1296 *  
1297 *   return 0;
1298 *   }
1299 * @endcode
1300
1301
1302<a name="ann-include/agglomeration_accessor.h"></a>
1303<h1>Annotated version of include/agglomeration_accessor.h</h1>
1304 *
1305 *
1306 *
1307 *
1308 * @code
1309 *   /* -----------------------------------------------------------------------------
1310 *   *
1311 *   * SPDX-License-Identifier: LGPL-2.1-or-later
1312 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
1313 *   * Andrea Cangiani
1314 *   *
1315 *   * This file is part of the deal.II code gallery.
1316 *   *
1317 *   * -----------------------------------------------------------------------------
1318 *   */
1319 *  
1320 *   #ifndef agglomeration_accessor_h
1321 *   #define agglomeration_accessor_h
1322 *  
1323 *   #include <deal.II/base/config.h>
1324 *  
1325 *   #include <deal.II/base/bounding_box.h>
1326 *   #include <deal.II/base/iterator_range.h>
1327 *  
1328 *   #include <deal.II/grid/filtered_iterator.h>
1329 *  
1330 *   #include <vector>
1331 *  
1332 *   using namespace dealii;
1333 *  
1334 *  
1335 * @endcode
1336 *
1337 * Forward declarations
1338 *
1339 * @code
1340 *   #ifndef DOXYGEN
1341 *   template <int, int>
1342 *   class AgglomerationHandler;
1343 *   template <int, int>
1344 *   class AgglomerationIterator;
1345 *   #endif
1346 *  
1347 *  
1348 *  
1351 *   template <int dim, int spacedim = dim>
1352 *   class AgglomerationAccessor
1353 *   {
1354 *   public:
1355 *  
1358 *   using AgglomerationContainer =
1359 *   std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>;
1360 *  
1361 *  
1362 *  
1365 *   void
1366 *   get_dof_indices(std::vector<types::global_dof_index> &) const;
1367 *  
1368 *  
1374 *   unsigned int
1375 *   n_faces() const;
1376 *  
1377 *  
1380 *   unsigned int
1381 *   n_agglomerated_faces() const;
1382 *  
1383 *  
1386 *   const AgglomerationIterator<dim, spacedim>
1387 *   neighbor(const unsigned int f) const;
1388 *  
1389 *  
1393 *   unsigned int
1394 *   neighbor_of_agglomerated_neighbor(const unsigned int f) const;
1395 *  
1396 *  
1405 *   bool
1406 *   at_boundary(const unsigned int f) const;
1407 *  
1408 *  
1411 *   const std::vector<typename Triangulation<dim>::active_face_iterator> &
1412 *   polytope_boundary() const;
1413 *  
1414 *  
1418 *   double
1419 *   volume() const;
1420 *  
1421 *  
1424 *   double
1425 *   diameter() const;
1426 *  
1427 *  
1430 *   AgglomerationContainer
1431 *   get_agglomerate() const;
1432 *  
1433 *  
1438 *   const BoundingBox<dim> &
1439 *   get_bounding_box() const;
1440 *  
1441 *  
1445 *   index() const;
1446 *  
1447 *  
1454 *   as_dof_handler_iterator(const DoFHandler<dim, spacedim> &dof_handler) const;
1455 *  
1456 *  
1460 *   unsigned int
1461 *   n_background_cells() const;
1462 *  
1463 *   /* Returns true if this polygon is owned by the current processor. On a serial
1464 *   * Triangulation this returs always true, but may yield false for a
1465 *   * parallel::distributed::Triangulation.
1466 *   */
1467 *   bool
1468 *   is_locally_owned() const;
1469 *  
1470 *  
1475 *   CellId
1476 *   id() const;
1477 *  
1478 *  
1483 *   subdomain_id() const;
1484 *  
1485 *  
1488 *   inline const std::vector<types::global_cell_index> &
1489 *   children() const;
1490 *  
1491 *  
1497 *   get_fe() const;
1498 *  
1499 *  
1504 *   void
1505 *   set_active_fe_index(const types::fe_index index) const;
1506 *  
1507 *  
1513 *   active_fe_index() const;
1514 *  
1515 *   private:
1516 *  
1520 *   AgglomerationAccessor();
1521 *  
1522 *  
1527 *   AgglomerationAccessor(
1529 *   &master_cell,
1530 *   const AgglomerationHandler<dim, spacedim> *ah);
1531 *  
1532 *  
1535 *   AgglomerationAccessor(
1537 *   const CellId &cell_id,
1538 *   const AgglomerationHandler<dim, spacedim> *ah);
1539 *  
1540 *  
1543 *   ~AgglomerationAccessor() = default;
1544 *  
1545 *  
1546 *  
1550 *  
1551 *  
1554 *   types::global_cell_index present_index;
1555 *  
1556 *  
1559 *   CellId present_id;
1560 *  
1561 *  
1564 *   types::subdomain_id present_subdomain_id;
1565 *  
1566 *  
1569 *   AgglomerationHandler<dim, spacedim> *handler;
1570 *  
1571 *  
1575 *   bool
1576 *   operator==(const AgglomerationAccessor<dim, spacedim> &other) const;
1577 *  
1578 *  
1581 *   bool
1582 *   operator!=(const AgglomerationAccessor<dim, spacedim> &other) const;
1583 *  
1584 *  
1587 *   void
1588 *   next();
1589 *  
1590 *  
1593 *   void
1594 *   prev();
1595 *  
1596 *  
1599 *   const AgglomerationContainer &
1600 *   get_slaves() const;
1601 *  
1602 *   unsigned int
1603 *   n_agglomerated_faces_per_cell(
1605 *   const;
1606 *  
1607 *   template <int, int>
1608 *   friend class AgglomerationIterator;
1609 *   };
1610 *  
1611 *  
1612 *  
1613 *   template <int dim, int spacedim>
1614 *   unsigned int
1615 *   AgglomerationAccessor<dim, spacedim>::n_agglomerated_faces_per_cell(
1616 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &cell) const
1617 *   {
1618 *   unsigned int n_neighbors = 0;
1619 *   for (const auto &f : cell->face_indices())
1620 *   {
1621 *   const auto &neighboring_cell = cell->neighbor(f);
1622 *   if ((cell->face(f)->at_boundary()) ||
1623 *   (neighboring_cell->is_active() &&
1624 *   !handler->are_cells_agglomerated(cell, neighboring_cell)))
1625 *   {
1626 *   ++n_neighbors;
1627 *   }
1628 *   }
1629 *   return n_neighbors;
1630 *   }
1631 *  
1632 *  
1633 *  
1634 *   template <int dim, int spacedim>
1635 *   unsigned int
1636 *   AgglomerationAccessor<dim, spacedim>::n_faces() const
1637 *   {
1638 *   Assert(!handler->is_slave_cell(master_cell),
1639 *   ExcMessage("You cannot pass a slave cell."));
1640 *   return handler->number_of_agglomerated_faces[present_index];
1641 *   }
1642 *  
1643 *  
1644 *  
1645 *   template <int dim, int spacedim>
1646 *   const AgglomerationIterator<dim, spacedim>
1647 *   AgglomerationAccessor<dim, spacedim>::neighbor(const unsigned int f) const
1648 *   {
1649 *   if (!at_boundary(f))
1650 *   {
1651 *   if (master_cell->is_ghost())
1652 *   {
1653 * @endcode
1654 *
1655 * The following path is needed when the present function is called
1656 * from neighbor_of_neighbor()
1657 *
1658
1659 *
1660 *
1661 * @code
1662 *   const unsigned int sender_rank = master_cell->subdomain_id();
1663 *  
1664 *   const CellId &master_id_ghosted_neighbor =
1665 *   handler->recv_ghosted_master_id.at(sender_rank)
1666 *   .at(present_id)
1667 *   .at(f);
1668 *  
1669 * @endcode
1670 *
1671 * Use the id of the master cell to uniquely identify the neighboring
1672 * agglomerate
1673 *
1674
1675 *
1676 *
1677 * @code
1678 *   return {master_cell,
1679 *   master_id_ghosted_neighbor,
1680 *   handler}; // dummy master?
1681 *   }
1682 *  
1683 *   const types::global_cell_index polytope_index =
1684 *   handler->master2polygon.at(master_cell->active_cell_index());
1685 *  
1686 *   const auto &neigh =
1687 *   handler->polytope_cache.cell_face_at_boundary.at({polytope_index, f})
1688 *   .second;
1689 *  
1690 *  
1691 *   if (neigh->is_locally_owned())
1692 *   {
1694 *   *neigh, &(handler->agglo_dh));
1695 *   return {cell_dh, handler};
1696 *   }
1697 *   else
1698 *   {
1699 * @endcode
1700 *
1701 * Get master_id from the neighboring ghost polytope. This uniquely
1702 * identifies the neighboring polytope among all processors.
1703 *
1704 * @code
1705 *   const CellId &master_id_neighbor =
1706 *   handler->polytope_cache.ghosted_master_id.at({present_id, f});
1707 *  
1708 * @endcode
1709 *
1710 * Use the id of the master cell to uniquely identify the neighboring
1711 * agglomerate
1712 *
1713 * @code
1714 *   return {neigh, master_id_neighbor, handler};
1715 *   }
1716 *   }
1717 *   else
1718 *   {
1719 *   return {};
1720 *   }
1721 *   }
1722 *  
1723 *  
1724 *  
1725 *   template <int dim, int spacedim>
1726 *   unsigned int
1727 *   AgglomerationAccessor<dim, spacedim>::neighbor_of_agglomerated_neighbor(
1728 *   const unsigned int f) const
1729 *   {
1730 * @endcode
1731 *
1732 * First, make sure it's not a boundary face.
1733 *
1734 * @code
1735 *   if (!at_boundary(f))
1736 *   {
1737 *   const auto &neigh_polytope =
1738 *   neighbor(f); // returns the neighboring master and id
1739 *  
1740 *   AssertThrow(neigh_polytope.state() == IteratorState::valid,
1741 *   ExcInternalError());
1742 *  
1743 *   unsigned int n_faces_agglomerated_neighbor;
1744 *  
1745 * @endcode
1746 *
1747 * if it is locally owned, retrieve the number of faces
1748 *
1749 * @code
1750 *   if (neigh_polytope->is_locally_owned())
1751 *   {
1752 *   n_faces_agglomerated_neighbor = neigh_polytope->n_faces();
1753 *   }
1754 *   else
1755 *   {
1756 * @endcode
1757 *
1758 * The neighboring polytope is not locally owned. We need to get the
1759 * number of its faces from the neighboring rank.
1760 *
1761
1762 *
1763 * First, retrieve the CellId of the neighboring polytope.
1764 *
1765 * @code
1766 *   const CellId &master_id_neighbor = neigh_polytope->id();
1767 *  
1768 * @endcode
1769 *
1770 * Then, get the neighboring rank
1771 *
1772 * @code
1773 *   const unsigned int sender_rank = neigh_polytope->subdomain_id();
1774 *  
1775 * @endcode
1776 *
1777 * From the neighboring rank, use the CellId of the neighboring
1778 * polytope to get the number of its faces.
1779 *
1780 * @code
1781 *   n_faces_agglomerated_neighbor =
1782 *   handler->recv_n_faces.at(sender_rank).at(master_id_neighbor);
1783 *   }
1784 *  
1785 *  
1786 * @endcode
1787 *
1788 * Loop over all faces of neighboring agglomerate
1789 *
1790 * @code
1791 *   for (unsigned int f_out = 0; f_out < n_faces_agglomerated_neighbor;
1792 *   ++f_out)
1793 *   {
1794 * @endcode
1795 *
1796 * Check if same CellId
1797 *
1798 * @code
1799 *   if (neigh_polytope->neighbor(f_out).state() == IteratorState::valid)
1800 *   if (neigh_polytope->neighbor(f_out)->id() == present_id)
1801 *   return f_out;
1802 *   }
1803 *   return numbers::invalid_unsigned_int;
1804 *   }
1805 *   else
1806 *   {
1807 * @endcode
1808 *
1809 * Face is at boundary
1810 *
1811 * @code
1812 *   return numbers::invalid_unsigned_int;
1813 *   }
1814 *   }
1815 *  
1816 * @endcode
1817 *
1818 * ------------------------------ inline functions -------------------------
1819 *
1820
1821 *
1822 *
1823 * @code
1824 *   template <int dim, int spacedim>
1825 *   inline AgglomerationAccessor<dim, spacedim>::AgglomerationAccessor()
1826 *   {}
1827 *  
1828 *  
1829 *  
1830 *   template <int dim, int spacedim>
1831 *   inline AgglomerationAccessor<dim, spacedim>::AgglomerationAccessor(
1832 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &cell,
1833 *   const AgglomerationHandler<dim, spacedim> *ah)
1834 *   {
1835 *   handler = const_cast<AgglomerationHandler<dim, spacedim> *>(ah);
1836 *   if (&(*handler->master_cells_container.end()) == std::addressof(cell))
1837 *   {
1838 *   present_index = handler->master_cells_container.size();
1839 *   master_cell = *handler->master_cells_container.end();
1840 *   present_id = CellId(); // invalid id (TODO)
1841 *   present_subdomain_id = numbers::invalid_subdomain_id;
1842 *   }
1843 *   else
1844 *   {
1845 *   present_index = handler->master2polygon.at(cell->active_cell_index());
1846 *   master_cell = cell;
1847 *   present_id = master_cell->id();
1848 *   present_subdomain_id = master_cell->subdomain_id();
1849 *   }
1850 *   }
1851 *  
1852 *  
1853 *  
1854 *   template <int dim, int spacedim>
1855 *   inline AgglomerationAccessor<dim, spacedim>::AgglomerationAccessor(
1856 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &neigh_cell,
1857 *   const CellId &master_cell_id,
1858 *   const AgglomerationHandler<dim, spacedim> *ah)
1859 *   {
1860 *   Assert(neigh_cell->is_ghost(), ExcInternalError());
1861 * @endcode
1862 *
1863 * neigh_cell is ghosted
1864 *
1865
1866 *
1867 *
1868 * @code
1869 *   handler = const_cast<AgglomerationHandler<dim, spacedim> *>(ah);
1870 *   master_cell = neigh_cell;
1871 *   present_index = numbers::invalid_unsigned_int;
1872 * @endcode
1873 *
1874 * neigh_cell is ghosted, use the CellId of that agglomerate
1875 *
1876 * @code
1877 *   present_id = master_cell_id;
1878 *   present_subdomain_id = master_cell->subdomain_id();
1879 *   }
1880 *  
1881 *  
1882 *  
1883 *   template <int dim, int spacedim>
1884 *   inline void
1885 *   AgglomerationAccessor<dim, spacedim>::get_dof_indices(
1886 *   std::vector<types::global_dof_index> &dof_indices) const
1887 *   {
1888 *   Assert(dof_indices.size() > 0,
1889 *   ExcMessage(
1890 *   "The vector of DoFs indices must be already properly resized."));
1891 *   if (is_locally_owned())
1892 *   {
1893 * @endcode
1894 *
1895 * Forward the call to the master cell
1896 *
1897 * @code
1898 *   typename DoFHandler<dim, spacedim>::cell_iterator master_cell_dh(
1899 *   *master_cell, &(handler->agglo_dh));
1900 *   master_cell_dh->get_dof_indices(dof_indices);
1901 *   }
1902 *   else
1903 *   {
1904 *   const std::vector<types::global_dof_index> &recv_dof_indices =
1905 *   handler->recv_ghost_dofs.at(present_subdomain_id).at(present_id);
1906 *  
1907 *   std::copy(recv_dof_indices.cbegin(),
1908 *   recv_dof_indices.cend(),
1909 *   dof_indices.begin());
1910 *   }
1911 *   }
1912 *  
1913 *  
1914 *  
1915 *   template <int dim, int spacedim>
1916 *   inline typename AgglomerationAccessor<dim, spacedim>::AgglomerationContainer
1917 *   AgglomerationAccessor<dim, spacedim>::get_agglomerate() const
1918 *   {
1919 *   auto agglomeration = get_slaves();
1920 *   agglomeration.push_back(master_cell);
1921 *   return agglomeration;
1922 *   }
1923 *  
1924 *  
1925 *  
1926 *   template <int dim, int spacedim>
1927 *   inline const std::vector<typename Triangulation<dim>::active_face_iterator> &
1928 *   AgglomerationAccessor<dim, spacedim>::polytope_boundary() const
1929 *   {
1930 *   return handler->polygon_boundary[master_cell];
1931 *   }
1932 *  
1933 *  
1934 *  
1935 *   template <int dim, int spacedim>
1936 *   inline double
1937 *   AgglomerationAccessor<dim, spacedim>::diameter() const
1938 *   {
1939 *   Assert(!handler->is_slave_cell(master_cell),
1940 *   ExcMessage("The present function cannot be called for slave cells."));
1941 *  
1942 *   if (handler->is_master_cell(master_cell))
1943 *   {
1944 * @endcode
1945 *
1946 * Get the bounding box associated with the master cell
1947 *
1948 * @code
1949 *   const auto &bdary_pts =
1950 *   handler->bboxes[present_index].get_boundary_points();
1951 *   return (bdary_pts.second - bdary_pts.first).norm();
1952 *   }
1953 *   else
1954 *   {
1955 * @endcode
1956 *
1957 * Standard deal.II way to get the measure of a cell.
1958 *
1959 * @code
1960 *   return master_cell->diameter();
1961 *   }
1962 *   }
1963 *  
1964 *  
1965 *  
1966 *   template <int dim, int spacedim>
1967 *   inline const BoundingBox<dim> &
1968 *   AgglomerationAccessor<dim, spacedim>::get_bounding_box() const
1969 *   {
1970 *   if (is_locally_owned())
1971 *   return handler->bboxes[present_index];
1972 *   else
1973 *   return handler->recv_ghosted_bbox.at(present_subdomain_id).at(present_id);
1974 *   }
1975 *  
1976 *  
1977 *  
1978 *   template <int dim, int spacedim>
1979 *   inline double
1980 *   AgglomerationAccessor<dim, spacedim>::volume() const
1981 *   {
1982 *   Assert(!handler->is_slave_cell(master_cell),
1983 *   ExcMessage("The present function cannot be called for slave cells."));
1984 *  
1985 *   if (handler->is_master_cell(master_cell))
1986 *   {
1987 *   return handler->bboxes[present_index].volume();
1988 *   }
1989 *   else
1990 *   {
1991 *   return master_cell->measure();
1992 *   }
1993 *   }
1994 *  
1995 *  
1996 *  
1997 *   template <int dim, int spacedim>
1998 *   inline void
1999 *   AgglomerationAccessor<dim, spacedim>::next()
2000 *   {
2001 * @endcode
2002 *
2003 * Increment the present index and update the polytope
2004 *
2005 * @code
2006 *   ++present_index;
2007 *  
2008 * @endcode
2009 *
2010 * Make sure not to query the CellId if it's past the last
2011 *
2012 * @code
2013 *   if (present_index < handler->master_cells_container.size())
2014 *   {
2015 *   master_cell = handler->master_cells_container[present_index];
2016 *   present_id = master_cell->id();
2017 *   present_subdomain_id = master_cell->subdomain_id();
2018 *   }
2019 *   }
2020 *  
2021 *  
2022 *  
2023 *   template <int dim, int spacedim>
2024 *   inline void
2025 *   AgglomerationAccessor<dim, spacedim>::prev()
2026 *   {
2027 * @endcode
2028 *
2029 * Decrement the present index and update the polytope
2030 *
2031 * @code
2032 *   --present_index;
2033 *   master_cell = handler->master_cells_container[present_index];
2034 *   present_id = master_cell->id();
2035 *   }
2036 *  
2037 *  
2038 *   template <int dim, int spacedim>
2039 *   inline bool
2040 *   AgglomerationAccessor<dim, spacedim>::operator==(
2041 *   const AgglomerationAccessor<dim, spacedim> &other) const
2042 *   {
2043 *   return present_index == other.present_index;
2044 *   }
2045 *  
2046 *   template <int dim, int spacedim>
2047 *   inline bool
2048 *   AgglomerationAccessor<dim, spacedim>::operator!=(
2049 *   const AgglomerationAccessor<dim, spacedim> &other) const
2050 *   {
2051 *   return !(*this == other);
2052 *   }
2053 *  
2054 *  
2055 *  
2056 *   template <int dim, int spacedim>
2058 *   AgglomerationAccessor<dim, spacedim>::index() const
2059 *   {
2060 *   return present_index;
2061 *   }
2062 *  
2063 *  
2064 *  
2065 *   template <int dim, int spacedim>
2067 *   AgglomerationAccessor<dim, spacedim>::as_dof_handler_iterator(
2068 *   const DoFHandler<dim, spacedim> &dof_handler) const
2069 *   {
2070 * @endcode
2071 *
2072 * Forward the call to the master cell using the right DoFHandler.
2073 *
2074 * @code
2075 *   return master_cell->as_dof_handler_iterator(dof_handler);
2076 *   }
2077 *  
2078 *  
2079 *  
2080 *   template <int dim, int spacedim>
2081 *   inline const typename AgglomerationAccessor<dim,
2082 *   spacedim>::AgglomerationContainer &
2083 *   AgglomerationAccessor<dim, spacedim>::get_slaves() const
2084 *   {
2085 *   return handler->master2slaves.at(master_cell->active_cell_index());
2086 *   }
2087 *  
2088 *  
2089 *  
2090 *   template <int dim, int spacedim>
2091 *   inline unsigned int
2092 *   AgglomerationAccessor<dim, spacedim>::n_background_cells() const
2093 *   {
2094 *   AssertThrow(get_agglomerate().size() > 0, ExcMessage("Empty agglomeration."));
2095 *   return get_agglomerate().size();
2096 *   }
2097 *  
2098 *  
2099 *  
2100 *   template <int dim, int spacedim>
2101 *   unsigned int
2102 *   AgglomerationAccessor<dim, spacedim>::n_agglomerated_faces() const
2103 *   {
2104 *   const auto &agglomeration = get_agglomerate();
2105 *   unsigned int n_neighbors = 0;
2106 *   for (const auto &cell : agglomeration)
2107 *   n_neighbors += n_agglomerated_faces_per_cell(cell);
2108 *   return n_neighbors;
2109 *   }
2110 *  
2111 *  
2112 *  
2113 *   template <int dim, int spacedim>
2114 *   inline bool
2115 *   AgglomerationAccessor<dim, spacedim>::at_boundary(const unsigned int f) const
2116 *   {
2117 *   if (master_cell->is_ghost())
2118 *   {
2119 *   const unsigned int sender_rank = master_cell->subdomain_id();
2120 *   return handler->recv_bdary_info.at(sender_rank).at(present_id).at(f);
2121 *   }
2122 *   else
2123 *   {
2124 *   Assert(!handler->is_slave_cell(master_cell),
2125 *   ExcMessage(
2126 *   "This function should not be called for a slave cell."));
2127 *  
2128 *  
2130 *   *master_cell, &(handler->agglo_dh));
2131 *   return handler->at_boundary(cell_dh, f);
2132 *   }
2133 *   }
2134 *  
2135 *  
2136 *  
2137 *   template <int dim, int spacedim>
2138 *   inline bool
2139 *   AgglomerationAccessor<dim, spacedim>::is_locally_owned() const
2140 *   {
2141 *   return master_cell->is_locally_owned();
2142 *   }
2143 *  
2144 *  
2145 *  
2146 *   template <int dim, int spacedim>
2147 *   inline CellId
2148 *   AgglomerationAccessor<dim, spacedim>::id() const
2149 *   {
2150 *   return present_id;
2151 *   }
2152 *  
2153 *  
2154 *  
2155 *   template <int dim, int spacedim>
2156 *   inline types::subdomain_id
2157 *   AgglomerationAccessor<dim, spacedim>::subdomain_id() const
2158 *   {
2159 *   return present_subdomain_id;
2160 *   }
2161 *  
2162 *   template <int dim, int spacedim>
2163 *   inline const std::vector<types::global_cell_index> &
2164 *   AgglomerationAccessor<dim, spacedim>::children() const
2165 *   {
2166 *   Assert(!handler->parent_child_info.empty(), ExcInternalError());
2167 *   return handler->parent_child_info.at(
2168 *   {present_index, handler->present_extraction_level});
2169 *   }
2170 *  
2171 *   template <int dim, int spacedim>
2172 *   inline const FiniteElement<dim, spacedim> &
2173 *   AgglomerationAccessor<dim, spacedim>::get_fe() const
2174 *   {
2176 *   master_cell_as_dof_handler_iterator =
2177 *   master_cell->as_dof_handler_iterator(handler->agglo_dh);
2178 *   return master_cell_as_dof_handler_iterator->get_fe();
2179 *   }
2180 *  
2181 *   template <int dim, int spacedim>
2182 *   inline void
2183 *   AgglomerationAccessor<dim, spacedim>::set_active_fe_index(
2184 *   const types::fe_index index) const
2185 *   {
2186 *   Assert(!handler->is_slave_cell(master_cell),
2187 *   ExcMessage("The present function cannot be called for slave cells."));
2189 *   master_cell_as_dof_handler_iterator =
2190 *   master_cell->as_dof_handler_iterator(handler->agglo_dh);
2191 *   master_cell_as_dof_handler_iterator->set_active_fe_index(index);
2192 *   }
2193 *  
2194 *   template <int dim, int spacedim>
2195 *   inline types::fe_index
2196 *   AgglomerationAccessor<dim, spacedim>::active_fe_index() const
2197 *   {
2199 *   master_cell_as_dof_handler_iterator =
2200 *   master_cell->as_dof_handler_iterator(handler->agglo_dh);
2201 *   return master_cell_as_dof_handler_iterator->active_fe_index();
2202 *   }
2203 *  
2204 *   #endif
2205 * @endcode
2206
2207
2208<a name="ann-include/agglomeration_handler.h"></a>
2209<h1>Annotated version of include/agglomeration_handler.h</h1>
2210 *
2211 *
2212 *
2213 *
2214 * @code
2215 *   /* -----------------------------------------------------------------------------
2216 *   *
2217 *   * SPDX-License-Identifier: LGPL-2.1-or-later
2218 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
2219 *   * Andrea Cangiani
2220 *   *
2221 *   * This file is part of the deal.II code gallery.
2222 *   *
2223 *   * -----------------------------------------------------------------------------
2224 *   */
2225 *  
2226 *   #ifndef agglomeration_handler_h
2227 *   #define agglomeration_handler_h
2228 *  
2229 *   #include <deal.II/base/mpi.h>
2230 *   #include <deal.II/base/quadrature.h>
2231 *   #include <deal.II/base/enable_observer_pointer.h>
2232 *  
2233 *   #include <deal.II/distributed/shared_tria.h>
2234 *   #include <deal.II/distributed/tria.h>
2235 *  
2236 *   #include <deal.II/dofs/dof_handler.h>
2237 *   #include <deal.II/dofs/dof_tools.h>
2238 *  
2239 *   #include <deal.II/fe/fe_dgp.h>
2240 *   #include <deal.II/fe/fe_dgq.h>
2241 *   #include <deal.II/fe/fe_nothing.h>
2242 *   #include <deal.II/fe/fe_simplex_p.h>
2243 *   #include <deal.II/fe/fe_system.h>
2244 *   #include <deal.II/fe/fe_values.h>
2245 *   #include <deal.II/fe/mapping_fe_field.h>
2246 *   #include <deal.II/fe/mapping_q.h>
2247 *  
2248 *   #include <deal.II/grid/grid_tools_cache.h>
2249 *   #include <deal.II/grid/tria.h>
2250 *  
2251 *   #include <deal.II/hp/fe_collection.h>
2252 *  
2253 *   #include <deal.II/lac/dynamic_sparsity_pattern.h>
2254 *   #include <deal.II/lac/la_parallel_vector.h>
2255 *   #include <deal.II/lac/sparse_matrix.h>
2256 *   #include <deal.II/lac/sparsity_pattern.h>
2257 *   #include <deal.II/lac/trilinos_sparse_matrix.h>
2258 *   #include <deal.II/lac/vector.h>
2259 *  
2260 *   #include <deal.II/meshworker/scratch_data.h>
2261 *  
2262 *   #include <deal.II/non_matching/fe_immersed_values.h>
2263 *   #include <deal.II/non_matching/immersed_surface_quadrature.h>
2264 *  
2265 *   #include <agglomeration_iterator.h>
2266 *   #include <agglomerator.h>
2267 *   #include <mapping_box.h>
2268 *  
2269 *   #include <fstream>
2270 *   #include <memory>
2271 *  
2272 *   using namespace dealii;
2273 *  
2274 * @endcode
2275 *
2276 * Forward declarations
2277 *
2278 * @code
2279 *   template <int dim, int spacedim>
2280 *   class AgglomerationHandler;
2281 *  
2282 *   namespace dealii
2283 *   {
2284 *   namespace internal
2285 *   {
2286 *  
2289 *   template <int, int>
2290 *   class AgglomerationHandlerImplementation;
2291 *   } // namespace internal
2292 *   } // namespace dealii
2293 *  
2294 *  
2295 *  
2296 *  
2300 *   namespace dealii
2301 *   {
2302 *   namespace internal
2303 *   {
2304 *   template <int dim, int spacedim>
2305 *   class PolytopeCache
2306 *   {
2307 *   public:
2308 *  
2311 *   PolytopeCache() = default;
2312 *  
2313 *  
2316 *   ~PolytopeCache() = default;
2317 *  
2318 *   void
2319 *   clear()
2320 *   {
2321 * @endcode
2322 *
2323 * clear all the members
2324 *
2325 * @code
2326 *   cell_face_at_boundary.clear();
2327 *   interface.clear();
2328 *   visited_cell_and_faces.clear();
2329 *   }
2330 *  
2331 *  
2338 *   mutable std::set<std::pair<types::global_cell_index, unsigned int>>
2339 *   visited_cell_and_faces;
2340 *  
2341 *  
2342 *   mutable std::set<std::pair<CellId, unsigned int>>
2343 *   visited_cell_and_faces_id;
2344 *  
2345 *  
2346 *  
2347 *  
2355 *   mutable std::map<
2356 *   std::pair<types::global_cell_index, unsigned int>,
2357 *   std::pair<bool,
2359 *   cell_face_at_boundary;
2360 *  
2361 *  
2365 *   mutable std::map<std::pair<CellId, unsigned int>, CellId>
2366 *   ghosted_master_id;
2367 *  
2368 *  
2378 *   mutable std::map<
2379 *   std::pair<CellId, CellId>,
2380 *   std::vector<
2381 *   std::pair<typename Triangulation<dim, spacedim>::active_cell_iterator,
2382 *   unsigned int>>>
2383 *   interface;
2384 *   };
2385 *   } // namespace internal
2386 *   } // namespace dealii
2387 *  
2388 *  
2389 *  
2392 *   template <int dim, int spacedim = dim>
2393 *   class AgglomerationHandler : public EnableObserverPointer
2394 *   {
2395 *   public:
2396 *   using agglomeration_iterator = AgglomerationIterator<dim, spacedim>;
2397 *  
2398 *   using AgglomerationContainer =
2399 *   typename AgglomerationIterator<dim, spacedim>::AgglomerationContainer;
2400 *  
2401 *  
2402 *   enum CellAgglomerationType
2403 *   {
2404 *   master = 0,
2405 *   slave = 1
2406 *   };
2407 *  
2408 *  
2409 *  
2410 *   explicit AgglomerationHandler(
2411 *   const GridTools::Cache<dim, spacedim> &cached_tria);
2412 *  
2413 *   AgglomerationHandler() = default;
2414 *  
2415 *   ~AgglomerationHandler()
2416 *   {
2417 * @endcode
2418 *
2419 * disconnect the signal
2420 *
2421 * @code
2422 *   tria_listener.disconnect();
2423 *   }
2424 *  
2425 *  
2428 *   agglomeration_iterator
2429 *   begin() const;
2430 *  
2431 *  
2434 *   agglomeration_iterator
2435 *   begin();
2436 *  
2437 *  
2440 *   agglomeration_iterator
2441 *   end() const;
2442 *  
2443 *  
2446 *   agglomeration_iterator
2447 *   end();
2448 *  
2449 *  
2452 *   agglomeration_iterator
2453 *   last();
2454 *  
2455 *  
2460 *   polytope_iterators() const;
2461 *  
2462 *   template <int, int>
2463 *   friend class AgglomerationIterator;
2464 *  
2465 *   template <int, int>
2466 *   friend class AgglomerationAccessor;
2467 *  
2468 *  
2472 *   void
2473 *   distribute_agglomerated_dofs(const FiniteElement<dim> &fe_space);
2474 *  
2475 *  
2478 *   void
2479 *   distribute_agglomerated_dofs(
2480 *   const hp::FECollection<dim, spacedim> &fe_collection_in);
2481 *  
2482 *  
2487 *   void
2488 *   initialize_fe_values(
2489 *   const Quadrature<dim> &cell_quadrature = QGauss<dim>(1),
2491 *   const Quadrature<dim - 1> &face_quadrature = QGauss<dim - 1>(1),
2492 *   const UpdateFlags &face_flags = UpdateFlags::update_default);
2493 *  
2494 *  
2497 *   void
2498 *   initialize_fe_values(
2499 *   const hp::QCollection<dim> &cell_qcollection =
2502 *   const hp::QCollection<dim - 1> &face_qcollection =
2504 *   const UpdateFlags &face_flags = UpdateFlags::update_default);
2505 *  
2506 *  
2512 *   template <typename SparsityPatternType, typename Number = double>
2513 *   void
2514 *   create_agglomeration_sparsity_pattern(
2515 *   SparsityPatternType &sparsity_pattern,
2517 *   const bool keep_constrained_dofs = true,
2519 *  
2520 *  
2528 *   agglomeration_iterator
2529 *   define_agglomerate(const AgglomerationContainer &cells);
2530 *  
2531 *  
2541 *   agglomeration_iterator
2542 *   define_agglomerate(const AgglomerationContainer &cells,
2543 *   const unsigned int fecollection_size);
2544 *  
2545 *  
2546 *   inline const Triangulation<dim, spacedim> &
2547 *   get_triangulation() const;
2548 *  
2549 *   inline const FiniteElement<dim, spacedim> &
2550 *   get_fe() const;
2551 *  
2552 *   inline const Mapping<dim> &
2553 *   get_mapping() const;
2554 *  
2555 *   inline const MappingBox<dim> &
2556 *   get_agglomeration_mapping() const;
2557 *  
2558 *   inline const std::vector<BoundingBox<dim>> &
2559 *   get_local_bboxes() const;
2560 *  
2561 *  
2565 *   double
2566 *   get_mesh_size() const;
2567 *  
2569 *   cell_to_polytope_index(
2571 *   const;
2572 *  
2573 *   inline decltype(auto)
2574 *   get_interface() const;
2575 *  
2576 *  
2579 *   template <typename CellIterator>
2580 *   inline bool
2581 *   is_master_cell(const CellIterator &cell) const;
2582 *  
2583 *  
2587 *   inline const std::vector<
2589 *   get_slaves_of_idx(types::global_cell_index idx) const;
2590 *  
2591 *  
2593 *   get_relationships() const;
2594 *  
2595 *  
2601 *   inline std::vector<
2603 *   get_agglomerate(
2605 *   &master_cell) const;
2606 *  
2607 *  
2613 *   inline const DoFHandler<dim, spacedim> &
2614 *   get_dof_handler() const;
2615 *  
2616 *  
2619 *   unsigned int
2620 *   n_agglomerates() const;
2621 *  
2622 *  
2625 *   unsigned int
2626 *   n_agglomerated_faces_per_cell(
2628 *   const;
2629 *  
2630 *  
2633 *   const FEValues<dim, spacedim> &
2634 *   reinit(const AgglomerationIterator<dim, spacedim> &polytope) const;
2635 *  
2636 *  
2641 *   reinit(const AgglomerationIterator<dim, spacedim> &polytope,
2642 *   const unsigned int face_index) const;
2643 *  
2644 *  
2649 *   std::pair<const FEValuesBase<dim, spacedim> &,
2651 *   reinit_interface(const AgglomerationIterator<dim, spacedim> &polytope_in,
2652 *   const AgglomerationIterator<dim, spacedim> &neigh_polytope,
2653 *   const unsigned int local_in,
2654 *   const unsigned int local_outside) const;
2655 *  
2656 *  
2662 *   agglomerated_quadrature(
2663 *   const AgglomerationContainer &cells,
2665 *   &master_cell) const;
2666 *  
2667 *  
2668 *  
2677 *   inline bool
2678 *   at_boundary(
2680 *   const unsigned int f) const;
2681 *  
2682 *   inline unsigned int
2683 *   n_dofs_per_cell() const noexcept;
2684 *  
2685 *   inline types::global_dof_index
2686 *   n_dofs() const noexcept;
2687 *  
2688 *  
2689 *  
2690 *  
2695 *   inline const std::vector<typename Triangulation<dim>::active_face_iterator> &
2696 *   polytope_boundary(
2697 *   const typename Triangulation<dim>::active_cell_iterator &cell);
2698 *  
2699 *  
2700 *  
2703 *   DoFHandler<dim, spacedim> agglo_dh;
2704 *  
2705 *  
2708 *   DoFHandler<dim, spacedim> output_dh;
2709 *  
2710 *   std::unique_ptr<MappingBox<dim>> box_mapping;
2711 *  
2712 *  
2720 *   void
2721 *   setup_ghost_polytopes();
2722 *  
2723 *   void
2724 *   exchange_interface_values();
2725 *  
2726 * @endcode
2727 *
2728 * TODO: move it to private interface
2729 *
2730 * @code
2731 *   mutable std::map<
2732 *   types::subdomain_id,
2733 *   std::map<std::pair<CellId, unsigned int>, std::vector<Point<spacedim>>>>
2734 *   recv_qpoints;
2735 *  
2736 *   mutable std::map<
2737 *   types::subdomain_id,
2738 *   std::map<std::pair<CellId, unsigned int>, std::vector<double>>>
2739 *   recv_jxws;
2740 *  
2741 *   mutable std::map<
2742 *   types::subdomain_id,
2743 *   std::map<std::pair<CellId, unsigned int>, std::vector<Tensor<1, spacedim>>>>
2744 *   recv_normals;
2745 *  
2746 *   mutable std::map<
2747 *   types::subdomain_id,
2748 *   std::map<std::pair<CellId, unsigned int>, std::vector<std::vector<double>>>>
2749 *   recv_values;
2750 *  
2751 *   mutable std::map<types::subdomain_id,
2752 *   std::map<std::pair<CellId, unsigned int>,
2753 *   std::vector<std::vector<Tensor<1, spacedim>>>>>
2754 *   recv_gradients;
2755 *  
2756 *  
2760 *   inline const typename DoFHandler<dim, spacedim>::active_cell_iterator
2761 *   polytope_to_dh_iterator(const types::global_cell_index polytope_index) const;
2762 *  
2763 *  
2766 *   template <typename RtreeType>
2767 *   void
2768 *   connect_hierarchy(const CellsAgglomerator<dim, RtreeType> &agglomerator);
2769 *  
2770 *  
2774 *   inline const hp::FECollection<dim, spacedim> &
2775 *   get_fe_collection() const;
2776 *  
2777 *  
2780 *   inline bool
2781 *   used_fe_collection() const;
2782 *  
2783 *   private:
2784 *  
2787 *   void
2788 *   initialize_agglomeration_data(
2789 *   const std::unique_ptr<GridTools::Cache<dim, spacedim>> &cache_tria);
2790 *  
2791 *   void
2792 *   update_agglomerate(
2793 *   AgglomerationContainer &polytope,
2794 *   const typename Triangulation<dim, spacedim>::active_cell_iterator
2795 *   &master_cell);
2796 *  
2797 *  
2800 *   void
2801 *   connect_to_tria_signals()
2802 *   {
2803 * @endcode
2804 *
2805 * First disconnect existing connections
2806 *
2807 * @code
2808 *   tria_listener.disconnect();
2809 *   tria_listener = tria->signals.any_change.connect(
2810 *   [&]() { this->initialize_agglomeration_data(this->cached_tria); });
2811 *   }
2812 *  
2813 *  
2818 *  
2820 *   is_slave_cell_of(
2822 *  
2823 *  
2827 *   void
2828 *   create_bounding_box(const AgglomerationContainer &polytope);
2829 *  
2830 *  
2832 *   get_master_idx_of_cell(
2834 *   const;
2835 *  
2836 *  
2839 *   inline bool
2840 *   are_cells_agglomerated(
2843 *   &other_cell) const;
2844 *  
2845 *  
2853 *   void
2854 *   initialize_hp_structure();
2855 *  
2856 *  
2857 *  
2861 *   reinit_master(
2863 *   const unsigned int face_number,
2865 *   &agglo_isv_ptr) const;
2866 *  
2867 *  
2868 *  
2872 *   template <typename CellIterator>
2873 *   inline bool
2874 *   is_slave_cell(const CellIterator &cell) const;
2875 *  
2876 *  
2877 *  
2881 *   void
2882 *   setup_connectivity_of_agglomeration();
2883 *  
2884 *  
2885 *  
2888 *   unsigned int n_agglomerations;
2889 *  
2890 *  
2891 *  
2897 *   LinearAlgebra::distributed::Vector<float> master_slave_relationships;
2898 *  
2899 *  
2903 *   std::map<types::global_cell_index,
2905 *   master_slave_relationships_iterators;
2906 *  
2907 *   using ScratchData = MeshWorker::ScratchData<dim, spacedim>;
2908 *  
2909 *   mutable std::vector<types::global_cell_index> number_of_agglomerated_faces;
2910 *  
2911 *  
2916 *   mutable std::map<
2918 *   std::vector<typename Triangulation<dim>::active_face_iterator>>
2919 *   polygon_boundary;
2920 *  
2921 *  
2922 *  
2928 *   std::vector<BoundingBox<spacedim>> bboxes;
2929 *  
2930 * @endcode
2931 *
2932 *
2933 *
2934
2935 *
2936 *
2937
2938 *
2939 * n_faces
2940 *
2941 * @code
2942 *   mutable std::map<types::subdomain_id, std::map<CellId, unsigned int>>
2943 *   local_n_faces;
2944 *  
2945 *   mutable std::map<types::subdomain_id, std::map<CellId, unsigned int>>
2946 *   recv_n_faces;
2947 *  
2948 *  
2949 * @endcode
2950 *
2951 * CellId (including slaves)
2952 *
2953 * @code
2954 *   mutable std::map<types::subdomain_id, std::map<CellId, CellId>>
2955 *   local_cell_ids_neigh_cell;
2956 *  
2957 *   mutable std::map<types::subdomain_id, std::map<CellId, CellId>>
2958 *   recv_cell_ids_neigh_cell;
2959 *  
2960 *  
2961 * @endcode
2962 *
2963 * send to neighborign rank the information that
2964 * - current polytope id
2965 * - face f
2966 * has the following neighboring id.
2967 *
2968 * @code
2969 *   mutable std::map<types::subdomain_id,
2970 *   std::map<CellId, std::map<unsigned int, CellId>>>
2971 *   local_ghosted_master_id;
2972 *  
2973 *   mutable std::map<types::subdomain_id,
2974 *   std::map<CellId, std::map<unsigned int, CellId>>>
2975 *   recv_ghosted_master_id;
2976 *  
2977 * @endcode
2978 *
2979 * CellIds from neighboring rank
2980 *
2981 * @code
2982 *   mutable std::map<types::subdomain_id,
2983 *   std::map<CellId, std::map<unsigned int, bool>>>
2984 *   local_bdary_info;
2985 *  
2986 *   mutable std::map<types::subdomain_id,
2987 *   std::map<CellId, std::map<unsigned int, bool>>>
2988 *   recv_bdary_info;
2989 *  
2990 * @endcode
2991 *
2992 * Exchange neighboring bounding boxes
2993 *
2994 * @code
2995 *   mutable std::map<types::subdomain_id, std::map<CellId, BoundingBox<dim>>>
2996 *   local_ghosted_bbox;
2997 *  
2998 *   mutable std::map<types::subdomain_id, std::map<CellId, BoundingBox<dim>>>
2999 *   recv_ghosted_bbox;
3000 *  
3001 * @endcode
3002 *
3003 * Exchange DoF indices with ghosted polytopes
3004 *
3005 * @code
3006 *   mutable std::map<types::subdomain_id,
3007 *   std::map<CellId, std::vector<types::global_dof_index>>>
3008 *   local_ghost_dofs;
3009 *  
3010 *   mutable std::map<types::subdomain_id,
3011 *   std::map<CellId, std::vector<types::global_dof_index>>>
3012 *   recv_ghost_dofs;
3013 *  
3014 * @endcode
3015 *
3016 * Exchange qpoints
3017 *
3018 * @code
3019 *   mutable std::map<
3021 *   std::map<std::pair<CellId, unsigned int>, std::vector<Point<spacedim>>>>
3022 *   local_qpoints;
3023 *  
3024 * @endcode
3025 *
3026 * Exchange jxws
3027 *
3028 * @code
3029 *   mutable std::map<
3031 *   std::map<std::pair<CellId, unsigned int>, std::vector<double>>>
3032 *   local_jxws;
3033 *  
3034 * @endcode
3035 *
3036 * Exchange normals
3037 *
3038 * @code
3039 *   mutable std::map<
3041 *   std::map<std::pair<CellId, unsigned int>, std::vector<Tensor<1, spacedim>>>>
3042 *   local_normals;
3043 *  
3044 * @endcode
3045 *
3046 * Exchange values
3047 *
3048 * @code
3049 *   mutable std::map<
3051 *   std::map<std::pair<CellId, unsigned int>, std::vector<std::vector<double>>>>
3052 *   local_values;
3053 *  
3054 *   mutable std::map<types::subdomain_id,
3055 *   std::map<std::pair<CellId, unsigned int>,
3056 *   std::vector<std::vector<Tensor<1, spacedim>>>>>
3057 *   local_gradients;
3058 *  
3059 *  
3060 *  
3061 * @endcode
3062 *
3063 *
3064 *
3065
3066 *
3067 *
3068 * @code
3069 *   const Triangulation<dim, spacedim> *tria;
3070 *  
3071 *   const Mapping<dim, spacedim> *mapping;
3072 *  
3073 *   std::unique_ptr<GridTools::Cache<dim, spacedim>> cached_tria;
3074 *  
3075 *   const MPI_Comm communicator;
3076 *  
3077 * @endcode
3078 *
3079 * The FiniteElement space we have on each cell. Currently supported types are
3080 * FE_DGQ and FE_DGP elements.
3081 *
3082 * @code
3083 *   std::unique_ptr<FiniteElement<dim>> fe;
3084 *  
3085 *   hp::FECollection<dim, spacedim> fe_collection;
3086 *  
3087 *  
3091 *  
3092 *  
3093 *  
3097 *   mutable std::unique_ptr<ScratchData> standard_scratch;
3098 *  
3099 *  
3104 *   mutable std::unique_ptr<ScratchData> agglomerated_scratch;
3105 *  
3106 *  
3107 *   mutable std::unique_ptr<NonMatching::FEImmersedSurfaceValues<spacedim>>
3108 *   agglomerated_isv;
3109 *  
3110 *   mutable std::unique_ptr<NonMatching::FEImmersedSurfaceValues<spacedim>>
3111 *   agglomerated_isv_neigh;
3112 *  
3113 *   mutable std::unique_ptr<NonMatching::FEImmersedSurfaceValues<spacedim>>
3114 *   agglomerated_isv_bdary;
3115 *  
3116 *   boost::signals2::connection tria_listener;
3117 *  
3118 *   UpdateFlags agglomeration_flags;
3119 *  
3120 *   const UpdateFlags internal_agglomeration_flags =
3123 *  
3124 *   UpdateFlags agglomeration_face_flags;
3125 *  
3126 *   const UpdateFlags internal_agglomeration_face_flags =
3129 *  
3130 *   Quadrature<dim> agglomeration_quad;
3131 *  
3132 *   Quadrature<dim - 1> agglomeration_face_quad;
3133 *  
3134 * @endcode
3135 *
3136 * Associate the master cell to the slaves.
3137 *
3138 * @code
3139 *   std::unordered_map<
3141 *   std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>>
3142 *   master2slaves;
3143 *  
3144 * @endcode
3145 *
3146 * Map the master cell index with the polytope index
3147 *
3148 * @code
3149 *   std::map<types::global_cell_index, types::global_cell_index> master2polygon;
3150 *  
3151 *  
3152 *   std::vector<typename Triangulation<dim>::active_cell_iterator>
3153 *   master_disconnected;
3154 *  
3155 * @endcode
3156 *
3157 * Dummy FiniteElement objects needed only to generate quadratures
3158 *
3159
3160 *
3161 *
3162 * @code
3163 *  
3166 *   FE_Nothing<dim, spacedim> dummy_fe;
3167 *  
3168 *  
3171 *   std::unique_ptr<FEValues<dim, spacedim>> no_values;
3172 *  
3173 *  
3176 *   std::unique_ptr<FEFaceValues<dim, spacedim>> no_face_values;
3177 *  
3178 *  
3181 *   std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
3182 *   master_cells_container;
3183 *  
3184 *   friend class internal::AgglomerationHandlerImplementation<dim, spacedim>;
3185 *  
3186 *   internal::PolytopeCache<dim, spacedim> polytope_cache;
3187 *  
3188 *  
3192 *   bool hybrid_mesh;
3193 *  
3194 *   std::map<std::pair<types::global_cell_index, types::global_cell_index>,
3195 *   std::vector<types::global_cell_index>>
3196 *   parent_child_info;
3197 *  
3198 *   unsigned int present_extraction_level;
3199 *  
3200 * @endcode
3201 *
3202 * Support for hp::FECollection
3203 *
3204 * @code
3205 *   bool is_hp_collection = false; // Indicates whether hp::FECollection is used
3206 *   std::unique_ptr<hp::FECollection<dim, spacedim>>
3207 *   hp_fe_collection; // External input FECollection
3208 *  
3209 * @endcode
3210 *
3211 * Stores quadrature rules; these QCollections should have the same size as
3212 * hp_fe_collection
3213 *
3214 * @code
3215 *   hp::QCollection<dim> agglomeration_quad_collection;
3216 *   hp::QCollection<dim - 1> agglomeration_face_quad_collection;
3217 *  
3219 *   mapping_collection; // Contains only one mapping object
3221 *   dummy_fe_collection; // Similar to dummy_fe, but as an FECollection
3222 * @endcode
3223 *
3224 * containing only dummy_fe
3225 * Note: The above two variables provide an hp::FECollection interface but
3226 * actually contain only one element each.
3227 *
3228
3229 *
3230 * Analogous to no_values and no_face_values, but used when different cells
3231 * employ different FEs or quadratures
3232 *
3233 * @code
3234 *   std::unique_ptr<hp::FEValues<dim, spacedim>> hp_no_values;
3235 *   std::unique_ptr<hp::FEFaceValues<dim, spacedim>> hp_no_face_values;
3236 *   };
3237 *  
3238 *  
3239 *  
3240 * @endcode
3241 *
3242 * ------------------------------ inline functions -------------------------
3243 *
3244 * @code
3245 *   template <int dim, int spacedim>
3246 *   inline const FiniteElement<dim, spacedim> &
3247 *   AgglomerationHandler<dim, spacedim>::get_fe() const
3248 *   {
3249 *   return *fe;
3250 *   }
3251 *  
3252 *  
3253 *  
3254 *   template <int dim, int spacedim>
3255 *   inline const Mapping<dim> &
3256 *   AgglomerationHandler<dim, spacedim>::get_mapping() const
3257 *   {
3258 *   return *mapping;
3259 *   }
3260 *  
3261 *  
3262 *  
3263 *   template <int dim, int spacedim>
3264 *   inline const MappingBox<dim> &
3265 *   AgglomerationHandler<dim, spacedim>::get_agglomeration_mapping() const
3266 *   {
3267 *   return *box_mapping;
3268 *   }
3269 *  
3270 *  
3271 *  
3272 *   template <int dim, int spacedim>
3273 *   inline const Triangulation<dim, spacedim> &
3274 *   AgglomerationHandler<dim, spacedim>::get_triangulation() const
3275 *   {
3276 *   return *tria;
3277 *   }
3278 *  
3279 *  
3280 *   template <int dim, int spacedim>
3281 *   inline const std::vector<BoundingBox<dim>> &
3282 *   AgglomerationHandler<dim, spacedim>::get_local_bboxes() const
3283 *   {
3284 *   return bboxes;
3285 *   }
3286 *  
3287 *  
3288 *  
3289 *   template <int dim, int spacedim>
3291 *   AgglomerationHandler<dim, spacedim>::cell_to_polytope_index(
3292 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &cell) const
3293 *   {
3294 *   return master2polygon.at(cell->active_cell_index());
3295 *   }
3296 *  
3297 *  
3298 *  
3299 *   template <int dim, int spacedim>
3300 *   inline decltype(auto)
3301 *   AgglomerationHandler<dim, spacedim>::get_interface() const
3302 *   {
3303 *   return polytope_cache.interface;
3304 *   }
3305 *  
3306 *  
3307 *  
3308 *   template <int dim, int spacedim>
3310 *   AgglomerationHandler<dim, spacedim>::get_relationships() const
3311 *   {
3312 *   return master_slave_relationships;
3313 *   }
3314 *  
3315 *  
3316 *  
3317 *   template <int dim, int spacedim>
3318 *   inline std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
3319 *   AgglomerationHandler<dim, spacedim>::get_agglomerate(
3321 *   &master_cell) const
3322 *   {
3323 *   Assert(is_master_cell(master_cell), ExcInternalError());
3324 *   auto agglomeration = get_slaves_of_idx(master_cell->active_cell_index());
3325 *   agglomeration.push_back(master_cell);
3326 *   return agglomeration;
3327 *   }
3328 *  
3329 *  
3330 *  
3331 *   template <int dim, int spacedim>
3332 *   inline const DoFHandler<dim, spacedim> &
3333 *   AgglomerationHandler<dim, spacedim>::get_dof_handler() const
3334 *   {
3335 *   return agglo_dh;
3336 *   }
3337 *  
3338 *  
3339 *  
3340 *   template <int dim, int spacedim>
3341 *   inline const std::vector<
3343 *   AgglomerationHandler<dim, spacedim>::get_slaves_of_idx(
3344 *   types::global_cell_index idx) const
3345 *   {
3346 *   return master2slaves.at(idx);
3347 *   }
3348 *  
3349 *  
3350 *  
3351 *   template <int dim, int spacedim>
3352 *   template <typename CellIterator>
3353 *   inline bool
3354 *   AgglomerationHandler<dim, spacedim>::is_master_cell(
3355 *   const CellIterator &cell) const
3356 *   {
3357 *   return master_slave_relationships[cell->global_active_cell_index()] == -1;
3358 *   }
3359 *  
3360 *  
3361 *  
3362 *  
3366 *   template <int dim, int spacedim>
3367 *   template <typename CellIterator>
3368 *   inline bool
3369 *   AgglomerationHandler<dim, spacedim>::is_slave_cell(
3370 *   const CellIterator &cell) const
3371 *   {
3372 *   return master_slave_relationships[cell->global_active_cell_index()] >= 0;
3373 *   }
3374 *  
3375 *  
3376 *  
3377 *   template <int dim, int spacedim>
3378 *   inline bool
3379 *   AgglomerationHandler<dim, spacedim>::at_boundary(
3381 *   const unsigned int face_index) const
3382 *   {
3383 *   Assert(!is_slave_cell(cell),
3384 *   ExcMessage("This function should not be called for a slave cell."));
3385 *  
3386 *   return polytope_cache.cell_face_at_boundary
3387 *   .at({master2polygon.at(cell->active_cell_index()), face_index})
3388 *   .first;
3389 *   }
3390 *  
3391 *  
3392 *   template <int dim, int spacedim>
3393 *   inline unsigned int
3394 *   AgglomerationHandler<dim, spacedim>::n_dofs_per_cell() const noexcept
3395 *   {
3396 *   return fe->n_dofs_per_cell();
3397 *   }
3398 *  
3399 *  
3400 *  
3401 *   template <int dim, int spacedim>
3403 *   AgglomerationHandler<dim, spacedim>::n_dofs() const noexcept
3404 *   {
3405 *   return agglo_dh.n_dofs();
3406 *   }
3407 *  
3408 *  
3409 *  
3410 *   template <int dim, int spacedim>
3411 *   inline const std::vector<typename Triangulation<dim>::active_face_iterator> &
3412 *   AgglomerationHandler<dim, spacedim>::polytope_boundary(
3413 *   const typename Triangulation<dim>::active_cell_iterator &cell)
3414 *   {
3415 *   return polygon_boundary[cell];
3416 *   }
3417 *  
3418 *  
3419 *  
3420 *   template <int dim, int spacedim>
3422 *   AgglomerationHandler<dim, spacedim>::is_slave_cell_of(
3424 *   {
3425 *   return master_slave_relationships_iterators.at(cell->active_cell_index());
3426 *   }
3427 *  
3428 *  
3429 *  
3430 *   template <int dim, int spacedim>
3432 *   AgglomerationHandler<dim, spacedim>::get_master_idx_of_cell(
3433 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &cell) const
3434 *   {
3435 *   auto idx = master_slave_relationships[cell->global_active_cell_index()];
3436 *   if (idx == -1)
3437 *   return cell->global_active_cell_index();
3438 *   else
3439 *   return static_cast<types::global_cell_index>(idx);
3440 *   }
3441 *  
3442 *  
3443 *  
3444 *   template <int dim, int spacedim>
3445 *   inline bool
3446 *   AgglomerationHandler<dim, spacedim>::are_cells_agglomerated(
3448 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &other_cell)
3449 *   const
3450 *   {
3451 * @endcode
3452 *
3453 * if different subdomain, then **by construction** they will not be together
3454 * if (cell->subdomain_id() != other_cell->subdomain_id())
3455 * return false;
3456 * else
3457 *
3458 * @code
3459 *   return (get_master_idx_of_cell(cell) == get_master_idx_of_cell(other_cell));
3460 *   }
3461 *  
3462 *  
3463 *  
3464 *   template <int dim, int spacedim>
3465 *   inline unsigned int
3466 *   AgglomerationHandler<dim, spacedim>::n_agglomerates() const
3467 *   {
3468 *   return n_agglomerations;
3469 *   }
3470 *  
3471 *  
3472 *  
3473 *   template <int dim, int spacedim>
3475 *   AgglomerationHandler<dim, spacedim>::polytope_to_dh_iterator(
3476 *   const types::global_cell_index polytope_index) const
3477 *   {
3478 *   return master_cells_container[polytope_index]->as_dof_handler_iterator(
3479 *   agglo_dh);
3480 *   }
3481 *  
3482 *  
3483 *  
3484 *   template <int dim, int spacedim>
3485 *   AgglomerationIterator<dim, spacedim>
3486 *   AgglomerationHandler<dim, spacedim>::begin() const
3487 *   {
3488 *   Assert(n_agglomerations > 0,
3489 *   ExcMessage("No agglomeration has been performed."));
3490 *   return {*master_cells_container.begin(), this};
3491 *   }
3492 *  
3493 *  
3494 *  
3495 *   template <int dim, int spacedim>
3496 *   AgglomerationIterator<dim, spacedim>
3497 *   AgglomerationHandler<dim, spacedim>::begin()
3498 *   {
3499 *   Assert(n_agglomerations > 0,
3500 *   ExcMessage("No agglomeration has been performed."));
3501 *   return {*master_cells_container.begin(), this};
3502 *   }
3503 *  
3504 *  
3505 *  
3506 *   template <int dim, int spacedim>
3507 *   AgglomerationIterator<dim, spacedim>
3508 *   AgglomerationHandler<dim, spacedim>::end() const
3509 *   {
3510 *   Assert(n_agglomerations > 0,
3511 *   ExcMessage("No agglomeration has been performed."));
3512 *   return {*master_cells_container.end(), this};
3513 *   }
3514 *  
3515 *  
3516 *  
3517 *   template <int dim, int spacedim>
3518 *   AgglomerationIterator<dim, spacedim>
3519 *   AgglomerationHandler<dim, spacedim>::end()
3520 *   {
3521 *   Assert(n_agglomerations > 0,
3522 *   ExcMessage("No agglomeration has been performed."));
3523 *   return {*master_cells_container.end(), this};
3524 *   }
3525 *  
3526 *  
3527 *  
3528 *   template <int dim, int spacedim>
3529 *   AgglomerationIterator<dim, spacedim>
3530 *   AgglomerationHandler<dim, spacedim>::last()
3531 *   {
3532 *   Assert(n_agglomerations > 0,
3533 *   ExcMessage("No agglomeration has been performed."));
3534 *   return {master_cells_container.back(), this};
3535 *   }
3536 *  
3537 *  
3538 *  
3539 *   template <int dim, int spacedim>
3540 *   IteratorRange<
3541 *   typename AgglomerationHandler<dim, spacedim>::agglomeration_iterator>
3542 *   AgglomerationHandler<dim, spacedim>::polytope_iterators() const
3543 *   {
3544 *   return IteratorRange<
3545 *   typename AgglomerationHandler<dim, spacedim>::agglomeration_iterator>(
3546 *   begin(), end());
3547 *   }
3548 *  
3549 *   template <int dim, int spacedim>
3550 *   template <typename RtreeType>
3551 *   void
3552 *   AgglomerationHandler<dim, spacedim>::connect_hierarchy(
3553 *   const CellsAgglomerator<dim, RtreeType> &agglomerator)
3554 *   {
3555 *   parent_child_info = agglomerator.parent_node_to_children_nodes;
3556 *   present_extraction_level = agglomerator.extraction_level;
3557 *   }
3558 *  
3559 *   template <int dim, int spacedim>
3560 *   inline const hp::FECollection<dim, spacedim> &
3561 *   AgglomerationHandler<dim, spacedim>::get_fe_collection() const
3562 *   {
3563 *   return *hp_fe_collection;
3564 *   }
3565 *  
3566 *   template <int dim, int spacedim>
3567 *   inline bool
3568 *   AgglomerationHandler<dim, spacedim>::used_fe_collection() const
3569 *   {
3570 *   return is_hp_collection;
3571 *   }
3572 *  
3573 *  
3574 *   #endif
3575 * @endcode
3576
3577
3578<a name="ann-include/agglomeration_iterator.h"></a>
3579<h1>Annotated version of include/agglomeration_iterator.h</h1>
3580 *
3581 *
3582 *
3583 *
3584 * @code
3585 *   /* -----------------------------------------------------------------------------
3586 *   *
3587 *   * SPDX-License-Identifier: LGPL-2.1-or-later
3588 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
3589 *   * Andrea Cangiani
3590 *   *
3591 *   * This file is part of the deal.II code gallery.
3592 *   *
3593 *   * -----------------------------------------------------------------------------
3594 *   */
3595 *  
3596 *   #ifndef agglomeration_iterator_h
3597 *   #define agglomeration_iterator_h
3598 *  
3599 *  
3600 *   #include <agglomeration_accessor.h>
3601 *  
3602 *  
3603 *  
3608 *   template <int dim, int spacedim = dim>
3609 *   class AgglomerationIterator
3610 *   {
3611 *   public:
3612 *   using AgglomerationContainer =
3613 *   typename AgglomerationAccessor<dim, spacedim>::AgglomerationContainer;
3614 *  
3615 *  
3619 *   AgglomerationIterator();
3620 *  
3621 *  
3625 *   AgglomerationIterator(
3627 *   const AgglomerationHandler<dim, spacedim> *handler);
3628 *  
3629 *  
3632 *   AgglomerationIterator(
3634 *   &master_cell,
3635 *   const CellId &cell_id,
3636 *   const AgglomerationHandler<dim, spacedim> *handler);
3637 *  
3638 *  
3642 *   const AgglomerationAccessor<dim, spacedim> &
3643 *   operator*() const;
3644 *  
3645 *  
3648 *   AgglomerationAccessor<dim, spacedim> &
3649 *   operator*();
3650 *  
3651 *  
3657 *   const AgglomerationAccessor<dim, spacedim> *
3658 *   operator->() const;
3659 *  
3660 *  
3663 *   AgglomerationAccessor<dim, spacedim> *
3664 *   operator->();
3665 *  
3666 *  
3669 *   bool
3670 *   operator==(const AgglomerationIterator<dim, spacedim> &) const;
3671 *  
3672 *  
3675 *   bool
3676 *   operator!=(const AgglomerationIterator<dim, spacedim> &) const;
3677 *  
3678 *  
3683 *   AgglomerationIterator &
3684 *   operator++();
3685 *  
3686 *  
3691 *   AgglomerationIterator
3692 *   operator++(int);
3693 *  
3694 *  
3699 *   AgglomerationIterator &
3700 *   operator--();
3701 *  
3702 *  
3707 *   AgglomerationIterator
3708 *   operator--(int);
3709 *  
3710 *  
3714 *   state() const;
3715 *  
3716 *  
3720 *   master_cell() const;
3721 *  
3722 *  
3727 *   using iterator_category = std::bidirectional_iterator_tag;
3728 *   using value_type = AgglomerationAccessor<dim, spacedim>;
3729 *   using difference_type = std::ptrdiff_t;
3730 *   using pointer = AgglomerationAccessor<dim, spacedim> *;
3731 *   using reference = AgglomerationAccessor<dim, spacedim> &;
3732 *  
3733 *   private:
3734 *  
3737 *   AgglomerationAccessor<dim, spacedim> accessor;
3738 *   };
3739 *  
3740 *  
3741 *  
3742 * @endcode
3743 *
3744 * ------------------------------ inline functions -------------------------
3745 *
3746
3747 *
3748 *
3749 * @code
3750 *   template <int dim, int spacedim>
3751 *   inline AgglomerationIterator<dim, spacedim>::AgglomerationIterator()
3752 *   : accessor()
3753 *   {}
3754 *  
3755 *  
3756 *  
3757 *   template <int dim, int spacedim>
3758 *   inline AgglomerationIterator<dim, spacedim>::AgglomerationIterator(
3760 *   &master_cell,
3761 *   const AgglomerationHandler<dim, spacedim> *handler)
3762 *   : accessor(master_cell, handler)
3763 *   {}
3764 *  
3765 *   template <int dim, int spacedim>
3766 *   inline AgglomerationIterator<dim, spacedim>::AgglomerationIterator(
3768 *   &master_cell,
3769 *   const CellId &cell_id,
3770 *   const AgglomerationHandler<dim, spacedim> *handler)
3771 *   : accessor(master_cell, cell_id, handler)
3772 *   {}
3773 *  
3774 *  
3775 *  
3776 *   template <int dim, int spacedim>
3777 *   inline AgglomerationAccessor<dim, spacedim> &
3778 *   AgglomerationIterator<dim, spacedim>::operator*()
3779 *   {
3780 *   return accessor;
3781 *   }
3782 *  
3783 *  
3784 *  
3785 *   template <int dim, int spacedim>
3786 *   inline AgglomerationAccessor<dim, spacedim> *
3787 *   AgglomerationIterator<dim, spacedim>::operator->()
3788 *   {
3789 *   return &(this->operator*());
3790 *   }
3791 *  
3792 *  
3793 *  
3794 *   template <int dim, int spacedim>
3795 *   inline const AgglomerationAccessor<dim, spacedim> &
3796 *   AgglomerationIterator<dim, spacedim>::operator*() const
3797 *   {
3798 *   return accessor;
3799 *   }
3800 *  
3801 *  
3802 *  
3803 *   template <int dim, int spacedim>
3804 *   inline const AgglomerationAccessor<dim, spacedim> *
3805 *   AgglomerationIterator<dim, spacedim>::operator->() const
3806 *   {
3807 *   return &(this->operator*());
3808 *   }
3809 *  
3810 *  
3811 *  
3812 *   template <int dim, int spacedim>
3813 *   inline bool
3814 *   AgglomerationIterator<dim, spacedim>::operator!=(
3815 *   const AgglomerationIterator<dim, spacedim> &other) const
3816 *   {
3817 *   return accessor != other.accessor;
3818 *   }
3819 *  
3820 *  
3821 *  
3822 *   template <int dim, int spacedim>
3823 *   inline bool
3824 *   AgglomerationIterator<dim, spacedim>::operator==(
3825 *   const AgglomerationIterator<dim, spacedim> &other) const
3826 *   {
3827 *   return accessor == other.accessor;
3828 *   }
3829 *  
3830 *  
3831 *  
3832 *   template <int dim, int spacedim>
3833 *   inline AgglomerationIterator<dim, spacedim> &
3834 *   AgglomerationIterator<dim, spacedim>::operator++()
3835 *   {
3836 *   accessor.next();
3837 *   return *this;
3838 *   }
3839 *  
3840 *  
3841 *  
3842 *   template <int dim, int spacedim>
3843 *   inline AgglomerationIterator<dim, spacedim>
3844 *   AgglomerationIterator<dim, spacedim>::operator++(int)
3845 *   {
3846 *   AgglomerationIterator tmp(*this);
3847 *   operator++();
3848 *  
3849 *   return tmp;
3850 *   }
3851 *  
3852 *  
3853 *  
3854 *   template <int dim, int spacedim>
3855 *   inline AgglomerationIterator<dim, spacedim> &
3856 *   AgglomerationIterator<dim, spacedim>::operator--()
3857 *   {
3858 *   accessor.prev();
3859 *   return *this;
3860 *   }
3861 *  
3862 *  
3863 *  
3864 *   template <int dim, int spacedim>
3865 *   inline AgglomerationIterator<dim, spacedim>
3866 *   AgglomerationIterator<dim, spacedim>::operator--(int)
3867 *   {
3868 *   AgglomerationIterator tmp(*this);
3869 *   operator--();
3870 *  
3871 *   return tmp;
3872 *   }
3873 *  
3874 *  
3875 *  
3876 *   template <int dim, int spacedim>
3878 *   AgglomerationIterator<dim, spacedim>::state() const
3879 *   {
3880 *   return accessor.master_cell.state();
3881 *   }
3882 *  
3883 *  
3884 *  
3885 *   template <int dim, int spacedim>
3887 *   AgglomerationIterator<dim, spacedim>::master_cell() const
3888 *   {
3889 *   return accessor.master_cell;
3890 *   }
3891 *  
3892 *  
3893 *  
3894 *   #endif
3895 * @endcode
3896
3897
3898<a name="ann-include/agglomerator.h"></a>
3899<h1>Annotated version of include/agglomerator.h</h1>
3900 *
3901 *
3902 *
3903 *
3904 * @code
3905 *   /* -----------------------------------------------------------------------------
3906 *   *
3907 *   * SPDX-License-Identifier: LGPL-2.1-or-later
3908 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
3909 *   * Andrea Cangiani
3910 *   *
3911 *   * This file is part of the deal.II code gallery.
3912 *   *
3913 *   * -----------------------------------------------------------------------------
3914 *   */
3915 *  
3916 *   #ifndef agglomerator_h
3917 *   #define agglomerator_h
3918 *  
3919 *  
3920 *   #include <deal.II/base/config.h>
3921 *  
3922 *   #include <deal.II/base/bounding_box.h>
3923 *  
3924 *   #include <boost/geometry/algorithms/distance.hpp>
3925 *   #include <boost/geometry/index/rtree.hpp>
3926 *   #include <boost/geometry/strategies/strategies.hpp>
3927 *  
3928 *   template <int dim, int spacedim>
3929 *   class AgglomerationHandler;
3930 *  
3931 *   namespace dealii
3932 *   {
3933 *   namespace internal
3934 *   {
3935 *   template <typename Value,
3936 *   typename Options,
3937 *   typename Translator,
3938 *   typename Box,
3939 *   typename Allocators>
3940 *   struct Rtree_visitor
3941 *   : public boost::geometry::index::detail::rtree::visitor<
3942 *   Value,
3943 *   typename Options::parameters_type,
3944 *   Box,
3945 *   Allocators,
3946 *   typename Options::node_tag,
3947 *   true>::type
3948 *   {
3949 *   inline Rtree_visitor(
3950 *   const Translator &translator,
3951 *   const unsigned int target_level,
3952 *   std::vector<std::vector<typename Triangulation<
3953 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>>
3954 *   &agglomerates_,
3955 *   std::vector<types::global_cell_index> &n_nodes_per_level,
3956 *   std::map<std::pair<types::global_cell_index, types::global_cell_index>,
3957 *   std::vector<types::global_cell_index>> &parent_to_children);
3958 *  
3959 *  
3962 *   using InternalNode =
3963 *   typename boost::geometry::index::detail::rtree::internal_node<
3964 *   Value,
3965 *   typename Options::parameters_type,
3966 *   Box,
3967 *   Allocators,
3968 *   typename Options::node_tag>::type;
3969 *  
3970 *  
3973 *   using Leaf = typename boost::geometry::index::detail::rtree::leaf<
3974 *   Value,
3975 *   typename Options::parameters_type,
3976 *   Box,
3977 *   Allocators,
3978 *   typename Options::node_tag>::type;
3979 *  
3980 *  
3985 *   inline void
3986 *   operator()(const InternalNode &node);
3987 *  
3988 *  
3991 *   inline void
3992 *   operator()(const Leaf &);
3993 *  
3994 *  
3998 *   const Translator &translator;
3999 *  
4000 *  
4003 *   size_t level;
4004 *  
4005 *  
4009 *   size_t node_counter;
4010 *  
4011 *  
4015 *   const size_t target_level;
4016 *  
4017 *  
4022 *   std::vector<std::vector<typename Triangulation<
4023 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>>
4024 *   &agglomerates;
4025 *  
4026 *  
4029 *   std::vector<types::global_cell_index> &n_nodes_per_level;
4030 *  
4031 *  
4035 *   std::map<std::pair<types::global_cell_index, types::global_cell_index>,
4036 *   std::vector<types::global_cell_index>>
4037 *   &parent_node_to_children_nodes;
4038 *   };
4039 *  
4040 *  
4041 *  
4042 *   template <typename Value,
4043 *   typename Options,
4044 *   typename Translator,
4045 *   typename Box,
4046 *   typename Allocators>
4047 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::Rtree_visitor(
4048 *   const Translator &translator,
4049 *   const unsigned int target_level,
4050 *   std::vector<std::vector<typename Triangulation<
4051 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>>
4052 *   &agglomerates_,
4053 *   std::vector<types::global_cell_index> &n_nodes_per_level_,
4054 *   std::map<std::pair<types::global_cell_index, types::global_cell_index>,
4055 *   std::vector<types::global_cell_index>> &parent_to_children)
4056 *   : translator(translator)
4057 *   , level(0)
4058 *   , node_counter(0)
4059 *   , target_level(target_level)
4060 *   , agglomerates(agglomerates_)
4061 *   , n_nodes_per_level(n_nodes_per_level_)
4062 *   , parent_node_to_children_nodes(parent_to_children)
4063 *   {}
4064 *  
4065 *  
4066 *  
4067 *   template <typename Value,
4068 *   typename Options,
4069 *   typename Translator,
4070 *   typename Box,
4071 *   typename Allocators>
4072 *   void
4073 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::operator()(
4074 *   const Rtree_visitor::InternalNode &node)
4075 *   {
4076 *   using elements_type =
4077 *   typename boost::geometry::index::detail::rtree::elements_type<
4078 *   InternalNode>::type; // pairs of bounding box and pointer to child
4079 * @endcode
4080 *
4081 * node
4082 *
4083 * @code
4084 *   const elements_type &elements =
4085 *   boost::geometry::index::detail::rtree::elements(node);
4086 *  
4087 *   if (level < target_level)
4088 *   {
4089 *   size_t level_backup = level;
4090 *   ++level;
4091 *  
4092 *   for (typename elements_type::const_iterator it = elements.begin();
4093 *   it != elements.end();
4094 *   ++it)
4095 *   {
4096 *   boost::geometry::index::detail::rtree::apply_visitor(*this,
4097 *   *it->second);
4098 *   }
4099 *  
4100 *   level = level_backup;
4101 *   }
4102 *   else if (level == target_level)
4103 *   {
4104 *   const auto offset = agglomerates.size();
4105 *   agglomerates.resize(offset + 1);
4106 *   size_t level_backup = level;
4107 *  
4108 *   ++level;
4109 *   for (const auto &entry : elements)
4110 *   {
4111 *   boost::geometry::index::detail::rtree::apply_visitor(
4112 *   *this, *entry.second);
4113 *   }
4114 * @endcode
4115 *
4116 * Done with node number 'node_counter' on level target_level.
4117 *
4118
4119 *
4120 *
4121 * @code
4122 *   ++node_counter; // visited all children of an internal node
4123 *   n_nodes_per_level[target_level]++;
4124 *  
4125 *   level = level_backup;
4126 *   }
4127 *   else if (level > target_level)
4128 *   {
4129 * @endcode
4130 *
4131 * I am on a child (internal) node on a deeper level.
4132 *
4133
4134 *
4135 * Keep visiting until you go to the leafs.
4136 *
4137 * @code
4138 *   size_t level_backup = level;
4139 *  
4140 *   ++level;
4141 *  
4142 * @endcode
4143 *
4144 * looping through entries of node
4145 *
4146 * @code
4147 *   for (const auto &entry : elements)
4148 *   {
4149 *   boost::geometry::index::detail::rtree::apply_visitor(
4150 *   *this, *entry.second);
4151 *   }
4152 * @endcode
4153 *
4154 * done with node on level l > target_level (not just
4155 * "target_level+1).
4156 *
4157 * @code
4158 *   n_nodes_per_level[level_backup]++;
4159 *   const types::global_cell_index node_idx =
4160 *   n_nodes_per_level[level_backup] - 1; // so to start from 0
4161 *  
4162 *   parent_node_to_children_nodes[{n_nodes_per_level[level_backup - 1],
4163 *   level_backup - 1}]
4164 *   .push_back(node_idx);
4165 *  
4166 *   level = level_backup;
4167 *   }
4168 *   }
4169 *  
4170 *  
4171 *  
4172 *   template <typename Value,
4173 *   typename Options,
4174 *   typename Translator,
4175 *   typename Box,
4176 *   typename Allocators>
4177 *   void
4178 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::operator()(
4179 *   const Rtree_visitor::Leaf &leaf)
4180 *   {
4181 *   using elements_type =
4182 *   typename boost::geometry::index::detail::rtree::elements_type<
4183 *   Leaf>::type; // pairs of bounding box and pointer to child node
4184 *   const elements_type &elements =
4185 *   boost::geometry::index::detail::rtree::elements(leaf);
4186 *  
4187 *   if (level == target_level)
4188 *   {
4189 * @endcode
4190 *
4191 * If I want to extract from leaf node, i.e. the target_level is the
4192 * last one where leafs are grouped together.
4193 *
4194 * @code
4195 *   const auto offset = agglomerates.size();
4196 *   agglomerates.resize(offset + 1);
4197 *  
4198 *   for (const auto &it : elements)
4199 *   agglomerates[node_counter].push_back(it.second);
4200 *  
4201 *   ++node_counter;
4202 *   n_nodes_per_level[target_level]++;
4203 *   }
4204 *   else
4205 *   {
4206 *   for (const auto &it : elements)
4207 *   agglomerates[node_counter].push_back(it.second);
4208 *  
4209 *  
4210 *   if (level == target_level + 1)
4211 *   {
4212 *   const unsigned int node_idx = n_nodes_per_level[level];
4213 *  
4214 *   parent_node_to_children_nodes[{n_nodes_per_level[level - 1],
4215 *   level - 1}]
4216 *   .push_back(node_idx);
4217 *   n_nodes_per_level[level]++;
4218 *   }
4219 *   }
4220 *   }
4221 *   } // namespace internal
4222 *  
4223 *  
4224 *  
4225 *   /**
4226 *   * Helper class which handles agglomeration based on the R-tree data
4227 *   * structure. Notice that the R-tree type is assumed to be an R-star-tree.
4228 *   */
4229 *   template <int dim, typename RtreeType>
4230 *   class CellsAgglomerator
4231 *   {
4232 *   public:
4233 *   template <int, int>
4234 *   friend class ::AgglomerationHandler;
4235 *  
4236 *   /**
4237 *   * Constructor. It takes a given rtree and an integer representing the
4238 *   * index of the level to be extracted.
4239 *   */
4240 *   CellsAgglomerator(const RtreeType &rtree,
4241 *   const unsigned int extraction_level);
4242 *  
4243 *   /**
4244 *   * Extract agglomerates based on the current tree and the extraction level.
4245 *   * This function returns a reference to
4246 *   */
4247 *   const std::vector<
4248 *   std::vector<typename Triangulation<dim>::active_cell_iterator>> &
4249 *   extract_agglomerates();
4250 *  
4251 *   /**
4252 *   * Get total number of levels.
4253 *   */
4254 *   inline unsigned int
4255 *   get_n_levels() const;
4256 *  
4257 *   /**
4258 *   * Return the number of nodes present in level @p level.
4259 *   */
4260 *   inline types::global_cell_index
4261 *   get_n_nodes_per_level(const unsigned int level) const;
4262 *  
4263 *   /**
4264 *   * This function returns a map which associates to each node on level
4265 *   * @p extraction_level a list of children.
4266 *   */
4267 *   inline const std::map<
4268 *   std::pair<types::global_cell_index, types::global_cell_index>,
4269 *   std::vector<types::global_cell_index>> &
4270 *   get_hierarchy() const;
4271 *  
4272 *   private:
4273 *   /**
4274 *   * Raw pointer to the actual R-tree.
4275 *   */
4276 *   RtreeType *rtree;
4277 *  
4278 *   /**
4279 *   * Extraction level.
4280 *   */
4281 *   const unsigned int extraction_level;
4282 *  
4283 *   /**
4284 *   * Store agglomerates obtained after recursive extraction on nodes of
4285 *   * level @p extraction_level.
4286 *   */
4287 *   std::vector<std::vector<typename Triangulation<dim>::active_cell_iterator>>
4288 *   agglomerates_on_level;
4289 *  
4290 *   /**
4291 *   * Vector storing the number of nodes (and, ultimately, agglomerates) for
4292 *   * each level.
4293 *   */
4294 *   std::vector<types::global_cell_index> n_nodes_per_level;
4295 *  
4296 *   /**
4297 *   * Map which maps a node parent @n on level @p l to a vector of integers
4298 *   * which stores the index of children.
4299 *   */
4300 *   std::map<std::pair<types::global_cell_index, types::global_cell_index>,
4301 *   std::vector<types::global_cell_index>>
4302 *   parent_node_to_children_nodes;
4303 *   };
4304 *  
4305 *  
4306 *  
4307 *   template <int dim, typename RtreeType>
4308 *   CellsAgglomerator<dim, RtreeType>::CellsAgglomerator(
4309 *   const RtreeType &tree,
4310 *   const unsigned int extraction_level_)
4311 *   : extraction_level(extraction_level_)
4312 *   {
4313 *   rtree = const_cast<RtreeType *>(&tree);
4314 *   Assert(n_levels(*rtree), ExcMessage("At least two levels are needed."));
4315 *   }
4316 *  
4317 *  
4318 *  
4319 *   template <int dim, typename RtreeType>
4320 *   const std::vector<
4321 *   std::vector<typename Triangulation<dim>::active_cell_iterator>> &
4322 *   CellsAgglomerator<dim, RtreeType>::extract_agglomerates()
4323 *   {
4324 *   AssertThrow(extraction_level <= n_levels(*rtree),
4325 *   ExcInternalError("You are trying to extract level " +
4326 *   std::to_string(extraction_level) +
4327 *   " of the tree, but it only has a total of " +
4328 *   std::to_string(n_levels(*rtree)) +
4329 *   " levels."));
4330 *   using RtreeView =
4331 *   boost::geometry::index::detail::rtree::utilities::view<RtreeType>;
4332 *   RtreeView rtv(*rtree);
4333 *  
4334 *   n_nodes_per_level.resize(rtv.depth() +
4335 *   1); // store how many nodes we have for each level.
4336 *  
4337 *   if (rtv.depth() == 0)
4338 *   {
4339 * @endcode
4340 *
4341 * The below algorithm does not work for `rtv.depth()==0`, which might
4342 * happen if the number entries in the tree is too small.
4343 *
4344 * @code
4345 *   agglomerates_on_level.resize(1);
4346 *   agglomerates_on_level[0].resize(1);
4347 *   }
4348 *   else
4349 *   {
4350 *   const unsigned int target_level =
4351 *   std::min<unsigned int>(extraction_level, rtv.depth());
4352 *  
4353 *   internal::Rtree_visitor<typename RtreeView::value_type,
4354 *   typename RtreeView::options_type,
4355 *   typename RtreeView::translator_type,
4356 *   typename RtreeView::box_type,
4357 *   typename RtreeView::allocators_type>
4358 *   extractor_visitor(rtv.translator(),
4359 *   target_level,
4360 *   agglomerates_on_level,
4361 *   n_nodes_per_level,
4362 *   parent_node_to_children_nodes);
4363 *  
4364 *  
4365 *   rtv.apply_visitor(extractor_visitor);
4366 *   }
4367 *   return agglomerates_on_level;
4368 *   }
4369 *  
4370 *  
4371 *  
4372 * @endcode
4373 *
4374 * ------------------------------ inline functions -------------------------
4375 *
4376
4377 *
4378 *
4379
4380 *
4381 *
4382 * @code
4383 *   template <int dim, typename RtreeType>
4384 *   inline unsigned int
4385 *   CellsAgglomerator<dim, RtreeType>::get_n_levels() const
4386 *   {
4387 *   return n_levels(*rtree);
4388 *   }
4389 *  
4390 *  
4391 *  
4392 *   template <int dim, typename RtreeType>
4393 *   inline types::global_cell_index
4394 *   CellsAgglomerator<dim, RtreeType>::get_n_nodes_per_level(
4395 *   const unsigned int level) const
4396 *   {
4397 *   return n_nodes_per_level[level];
4398 *   }
4399 *  
4400 *  
4401 *  
4402 *   template <int dim, typename RtreeType>
4403 *   inline const std::map<
4404 *   std::pair<types::global_cell_index, types::global_cell_index>,
4405 *   std::vector<types::global_cell_index>> &
4406 *   CellsAgglomerator<dim, RtreeType>::get_hierarchy() const
4407 *   {
4408 *   Assert(parent_node_to_children_nodes.size(),
4409 *   ExcMessage(
4410 *   "The hierarchy has not been computed. Did you forget to call"
4411 *   " extract_agglomerates() first?"));
4412 *   return parent_node_to_children_nodes;
4413 *   }
4414 *   } // namespace dealii
4415 *   #endif
4416 * @endcode
4417
4418
4419<a name="ann-include/mapping_box.h"></a>
4420<h1>Annotated version of include/mapping_box.h</h1>
4421 *
4422 *
4423 *
4424 *
4425 * @code
4426 *   /* -----------------------------------------------------------------------------
4427 *   *
4428 *   * SPDX-License-Identifier: LGPL-2.1-or-later
4429 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
4430 *   * Andrea Cangiani
4431 *   *
4432 *   * This file is part of the deal.II code gallery.
4433 *   *
4434 *   * -----------------------------------------------------------------------------
4435 *   */
4436 *  
4437 *   #ifndef dealii_mapping_box_h
4438 *   #define dealii_mapping_box_h
4439 *  
4440 *  
4441 *   #include <deal.II/base/config.h>
4442 *  
4443 *   #include <deal.II/base/bounding_box.h>
4444 *   #include <deal.II/base/qprojector.h>
4445 *  
4446 *   #include <deal.II/fe/mapping.h>
4447 *  
4448 *   #include <cmath>
4449 *  
4450 *  
4451 *   DEAL_II_NAMESPACE_OPEN
4452 *  
4453 *   /**
4454 *   * @addtogroup mapping
4455 *   * @{
4456 *   */
4457 *  
4458 *   /**
4459 *   * A class providing a mapping from the reference cell to cells that are
4460 *   * axiparallel, i.e., that have the shape of rectangles (in 2d) or
4461 *   * boxes (in 3d) with edges parallel to the coordinate directions. The
4462 *   * class therefore provides functionality that is equivalent to what,
4463 *   * for example, MappingQ would provide for such cells. However, knowledge
4464 *   * of the shape of cells allows this class to be substantially more
4465 *   * efficient.
4466 *   *
4467 *   * Specifically, the mapping is meant for cells for which the mapping from
4468 *   * the reference to the real cell is a scaling along the coordinate
4469 *   * directions: The transformation from reference coordinates \hat {\mathbf
4470 *   * x} to real coordinates \mathbf x on each cell is of the form
4471 *   * @f{align*}{
4472 *   * {\mathbf x}(\hat {\mathbf x})
4473 *   * =
4474 *   * \begin{pmatrix}
4475 *   * h_x & 0 \\
4476 *   * 0 & h_y
4477 *   * \end{pmatrix}
4478 *   * \hat{\mathbf x}
4479 *   * + {\mathbf v}_0
4480 *   * @f}
4481 *   * in 2d, and
4482 *   * @f{align*}{
4483 *   * {\mathbf x}(\hat {\mathbf x})
4484 *   * =
4485 *   * \begin{pmatrix}
4486 *   * h_x & 0 & 0 \\
4487 *   * 0 & h_y & 0 \\
4488 *   * 0 & 0 & h_z
4489 *   * \end{pmatrix}
4490 *   * \hat{\mathbf x}
4491 *   * + {\mathbf v}_0
4492 *   * @f}
4493 *   * in 3d, where {\mathbf v}_0 is the bottom left vertex and h_x,h_y,h_z
4494 *   * are the extents of the cell along the axes.
4495 *   *
4496 *   * The class is intended for efficiency, and it does not do a whole lot of
4497 *   * error checking. If you apply this mapping to a cell that does not conform
4498 *   * to the requirements above, you will get strange results.
4499 *   */
4500 *   template <int dim, int spacedim = dim>
4501 *   class MappingBox : public Mapping<dim, spacedim>
4502 *   {
4503 *   public:
4504 *   MappingBox(const std::vector<BoundingBox<dim>> &local_boxes,
4505 *   const std::map<types::global_cell_index, types::global_cell_index>
4506 *   &polytope_translator);
4507 * @endcode
4508 *
4509 * for documentation, see the Mapping base class
4510 *
4511 * @code
4512 *   virtual std::unique_ptr<Mapping<dim, spacedim>>
4513 *   clone() const override;
4514 *  
4515 *   /**
4516 *   * Return @p true because MappingBox preserves vertex
4517 *   * locations.
4518 *   */
4519 *   virtual bool
4520 *   preserves_vertex_locations() const override;
4521 *  
4522 *   virtual bool
4523 *   is_compatible_with(
4524 *   #if DEAL_II_VERSION_GTE(9, 8, 0)
4525 *   const ReferenceCell<dim> &reference_cell
4526 *   #else
4527 *   const ReferenceCell &reference_cell
4528 *   #endif
4529 *   ) const override;
4530 *  
4531 *   /**
4532 *   * @name Mapping points between reference and real cells
4533 *   * @{
4534 *   */
4535 *  
4536 * @endcode
4537 *
4538 * for documentation, see the Mapping base class
4539 *
4540 * @code
4541 *   virtual Point<spacedim>
4542 *   transform_unit_to_real_cell(
4543 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4544 *   const Point<dim> &p) const override;
4545 *  
4546 * @endcode
4547 *
4548 * for documentation, see the Mapping base class
4549 *
4550 * @code
4551 *   virtual Point<dim>
4552 *   transform_real_to_unit_cell(
4553 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4554 *   const Point<spacedim> &p) const override;
4555 *  
4556 * @endcode
4557 *
4558 * for documentation, see the Mapping base class
4559 *
4560 * @code
4561 *   virtual void
4562 *   transform_points_real_to_unit_cell(
4563 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4564 *   const ArrayView<const Point<spacedim>> &real_points,
4565 *   const ArrayView<Point<dim>> &unit_points) const override;
4566 *  
4567 *   /**
4568 *   * @}
4569 *   */
4570 *  
4571 *   /**
4572 *   * @name Functions to transform tensors from reference to real coordinates
4573 *   * @{
4574 *   */
4575 *  
4576 * @endcode
4577 *
4578 * for documentation, see the Mapping base class
4579 *
4580 * @code
4581 *   virtual void
4582 *   transform(const ArrayView<const Tensor<1, dim>> &input,
4583 *   const MappingKind kind,
4584 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal,
4585 *   const ArrayView<Tensor<1, spacedim>> &output) const override;
4586 *  
4587 * @endcode
4588 *
4589 * for documentation, see the Mapping base class
4590 *
4591 * @code
4592 *   virtual void
4593 *   transform(const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
4594 *   const MappingKind kind,
4595 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal,
4596 *   const ArrayView<Tensor<2, spacedim>> &output) const override;
4597 *  
4598 * @endcode
4599 *
4600 * for documentation, see the Mapping base class
4601 *
4602 * @code
4603 *   virtual void
4604 *   transform(const ArrayView<const Tensor<2, dim>> &input,
4605 *   const MappingKind kind,
4606 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal,
4607 *   const ArrayView<Tensor<2, spacedim>> &output) const override;
4608 *  
4609 * @endcode
4610 *
4611 * for documentation, see the Mapping base class
4612 *
4613 * @code
4614 *   virtual void
4615 *   transform(const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
4616 *   const MappingKind kind,
4617 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal,
4618 *   const ArrayView<Tensor<3, spacedim>> &output) const override;
4619 *  
4620 * @endcode
4621 *
4622 * for documentation, see the Mapping base class
4623 *
4624 * @code
4625 *   virtual void
4626 *   transform(const ArrayView<const Tensor<3, dim>> &input,
4627 *   const MappingKind kind,
4628 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal,
4629 *   const ArrayView<Tensor<3, spacedim>> &output) const override;
4630 *  
4631 *   /**
4632 *   * @}
4633 *   */
4634 *  
4635 *   /**
4636 *   * @name Interface with FEValues
4637 *   * @{
4638 *   */
4639 *  
4640 *   /**
4641 *   * Storage for internal data of the mapping. See Mapping::InternalDataBase
4642 *   * for an extensive description.
4643 *   *
4644 *   * This includes data that is computed once when the object is created (in
4645 *   * get_data()) as well as data the class wants to store from between the
4646 *   * call to fill_fe_values(), fill_fe_face_values(), or
4647 *   * fill_fe_subface_values() until possible later calls from the finite
4648 *   * element to functions such as transform(). The latter class of member
4649 *   * variables are marked as 'mutable'.
4650 *   */
4651 *   class InternalData : public Mapping<dim, spacedim>::InternalDataBase
4652 *   {
4653 *   public:
4654 *   /**
4655 *   * Default constructor.
4656 *   */
4657 *   InternalData() = default;
4658 *  
4659 *   /**
4660 *   * Constructor that initializes the object with a quadrature.
4661 *   */
4662 *   InternalData(const Quadrature<dim> &quadrature);
4663 *  
4664 * @endcode
4665 *
4666 * Documentation see Mapping::InternalDataBase.
4667 *
4668 * @code
4669 *   virtual void
4670 *   reinit(const UpdateFlags update_flags,
4671 *   const Quadrature<dim> &quadrature) override;
4672 *  
4673 *   /**
4674 *   * Return an estimate (in bytes) for the memory consumption of this object.
4675 *   */
4676 *   virtual std::size_t
4677 *   memory_consumption() const override;
4678 *  
4679 *   /**
4680 *   * Extents of the last cell we have seen in the coordinate directions,
4681 *   * i.e., <i>h<sub>x</sub></i>, <i>h<sub>y</sub></i>, <i>h<sub>z</sub></i>.
4682 *   */
4683 *   mutable Tensor<1, dim> cell_extents;
4684 *  
4685 *   /**
4686 *   * Traslation term in F(\hat{x})=J\hat{x} + c.
4687 *   */
4688 *   mutable Tensor<1, dim> traslation;
4689 *  
4690 *   /**
4691 *   * Reciprocal of the extents of the last cell we have seen in the
4692 *   * coordinate directions, i.e., <i>h<sub>x</sub></i>,
4693 *   * <i>h<sub>y</sub></i>, <i>h<sub>z</sub></i>.
4694 *   */
4695 *   mutable Tensor<1, dim> inverse_cell_extents;
4696 *  
4697 *   /**
4698 *   * The volume element
4699 *   */
4700 *   mutable double volume_element;
4701 *  
4702 *   /**
4703 *   * Location of quadrature points of faces or subfaces in 3d with all
4704 *   * possible orientations. Can be accessed with the correct offset provided
4705 *   * via QProjector::DataSetDescriptor. Not needed/used for cells.
4706 *   */
4707 *   std::vector<Point<dim>> quadrature_points;
4708 *   };
4709 *  
4710 *   private:
4711 * @endcode
4712 *
4713 * documentation can be found in Mapping::requires_update_flags()
4714 *
4715 * @code
4716 *   virtual UpdateFlags
4717 *   requires_update_flags(const UpdateFlags update_flags) const override;
4718 *  
4719 * @endcode
4720 *
4721 * documentation can be found in Mapping::get_data()
4722 *
4723 * @code
4724 *   virtual std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
4725 *   get_data(const UpdateFlags, const Quadrature<dim> &quadrature) const override;
4726 *  
4727 *   using Mapping<dim, spacedim>::get_face_data;
4728 *  
4729 * @endcode
4730 *
4731 * documentation can be found in Mapping::get_subface_data()
4732 *
4733 * @code
4734 *   virtual std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
4735 *   get_subface_data(const UpdateFlags flags,
4736 *   const Quadrature<dim - 1> &quadrature) const override;
4737 *  
4738 * @endcode
4739 *
4740 * documentation can be found in Mapping::fill_fe_values()
4741 *
4742 * @code
4743 *   virtual CellSimilarity::Similarity
4744 *   fill_fe_values(
4745 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4746 *   const CellSimilarity::Similarity cell_similarity,
4747 *   const Quadrature<dim> &quadrature,
4748 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
4749 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4750 *   &output_data) const override;
4751 *  
4752 *   using Mapping<dim, spacedim>::fill_fe_face_values;
4753 *  
4754 * @endcode
4755 *
4756 * documentation can be found in Mapping::fill_fe_subface_values()
4757 *
4758 * @code
4759 *   virtual void
4760 *   fill_fe_subface_values(
4761 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4762 *   const unsigned int face_no,
4763 *   const unsigned int subface_no,
4764 *   const Quadrature<dim - 1> &quadrature,
4765 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
4766 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4767 *   &output_data) const override;
4768 *  
4769 * @endcode
4770 *
4771 * documentation can be found in Mapping::fill_fe_immersed_surface_values()
4772 *
4773 * @code
4774 *   virtual void
4775 *   fill_fe_immersed_surface_values(
4776 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4777 *   const NonMatching::ImmersedSurfaceQuadrature<dim> &quadrature,
4778 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
4779 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4780 *   &output_data) const override;
4781 *  
4782 *   /**
4783 *   * @}
4784 *   */
4785 *  
4786 *   /**
4787 *   * Update the cell_extents field of the incoming InternalData object with the
4788 *   * size of the incoming cell.
4789 *   */
4790 *   void
4791 *   update_cell_extents(
4792 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4793 *   const CellSimilarity::Similarity cell_similarity,
4794 *   const InternalData &data) const;
4795 *  
4796 *   /**
4797 *   * Compute the quadrature points if the UpdateFlags of the incoming
4798 *   * InternalData object say that they should be updated.
4799 *   *
4800 *   * Called from fill_fe_values.
4801 *   */
4802 *   void
4803 *   maybe_update_cell_quadrature_points(
4804 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
4805 *   const InternalData &data,
4806 *   const ArrayView<const Point<dim>> &unit_quadrature_points,
4807 *   std::vector<Point<dim>> &quadrature_points) const;
4808 *  
4809 *   /**
4810 *   * Compute the normal vectors if the UpdateFlags of the incoming InternalData
4811 *   * object say that they should be updated.
4812 *   */
4813 *   void
4814 *   maybe_update_normal_vectors(
4815 *   const unsigned int face_no,
4816 *   const InternalData &data,
4817 *   std::vector<Tensor<1, dim>> &normal_vectors) const;
4818 *  
4819 *   /**
4820 *   * Since the Jacobian is constant for this mapping all derivatives of the
4821 *   * Jacobian are identically zero. Fill these quantities with zeros if the
4822 *   * corresponding update flags say that they should be updated.
4823 *   */
4824 *   void
4825 *   maybe_update_jacobian_derivatives(
4826 *   const InternalData &data,
4827 *   const CellSimilarity::Similarity cell_similarity,
4828 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4829 *   &output_data) const;
4830 *  
4831 *  
4832 *   /**
4833 *   * Compute the volume elements if the UpdateFlags of the incoming
4834 *   * InternalData object say that they should be updated.
4835 *   */
4836 *   void
4837 *   maybe_update_volume_elements(const InternalData &data) const;
4838 *  
4839 *   /**
4840 *   * Compute the Jacobians if the UpdateFlags of the incoming
4841 *   * InternalData object say that they should be updated.
4842 *   */
4843 *   void
4844 *   maybe_update_jacobians(
4845 *   const InternalData &data,
4846 *   const CellSimilarity::Similarity cell_similarity,
4847 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4848 *   &output_data) const;
4849 *  
4850 *   /**
4851 *   * Compute the inverse Jacobians if the UpdateFlags of the incoming
4852 *   * InternalData object say that they should be updated.
4853 *   */
4854 *   void
4855 *   maybe_update_inverse_jacobians(
4856 *   const InternalData &data,
4857 *   const CellSimilarity::Similarity cell_similarity,
4858 *   internal::FEValuesImplementation::MappingRelatedData<dim, spacedim>
4859 *   &output_data) const;
4860 *  
4861 *   /**
4862 *   * Vector of (local) bounding boxes
4863 *   */
4864 *   std::vector<BoundingBox<dim>> boxes;
4865 *  
4866 *   /**
4867 *   * Map from global cell index to bounding box index
4868 *   */
4869 *   std::map<types::global_cell_index, types::global_cell_index>
4870 *   polytope_translator;
4871 *   };
4872 *  
4873 *   /** @} */
4874 *  
4875 *   DEAL_II_NAMESPACE_CLOSE
4876 *  
4877 *   #endif
4878 * @endcode
4879
4880
4881<a name="ann-include/poly_utils.h"></a>
4882<h1>Annotated version of include/poly_utils.h</h1>
4883 *
4884 *
4885 *
4886 *
4887 * @code
4888 *   /* -----------------------------------------------------------------------------
4889 *   *
4890 *   * SPDX-License-Identifier: LGPL-2.1-or-later
4891 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
4892 *   * Andrea Cangiani
4893 *   *
4894 *   * This file is part of the deal.II code gallery.
4895 *   *
4896 *   * -----------------------------------------------------------------------------
4897 *   */
4898 *  
4899 *   #ifndef poly_utils_h
4900 *   #define poly_utils_h
4901 *  
4902 *   #include <deal.II/base/config.h>
4903 *  
4904 *   #include <deal.II/base/conditional_ostream.h>
4905 *   #include <deal.II/base/point.h>
4906 *   #include <deal.II/base/quadrature.h>
4907 *   #include <deal.II/base/std_cxx20/iota_view.h>
4908 *  
4909 *   #include <deal.II/boost_adaptors/bounding_box.h>
4910 *   #include <deal.II/boost_adaptors/point.h>
4911 *   #include <deal.II/boost_adaptors/segment.h>
4912 *  
4913 *   #include <deal.II/distributed/tria.h>
4914 *  
4915 *   #include <deal.II/dofs/dof_handler.h>
4916 *  
4917 *   #include <deal.II/fe/fe_dgq.h>
4918 *   #include <deal.II/fe/fe_values.h>
4919 *  
4920 *   #include <deal.II/grid/grid_tools.h>
4921 *  
4922 *   #include <deal.II/lac/dynamic_sparsity_pattern.h>
4923 *   #include <deal.II/lac/sparse_matrix.h>
4924 *   #include <deal.II/lac/sparsity_pattern.h>
4925 *   #include <deal.II/lac/sparsity_tools.h>
4926 *   #include <deal.II/lac/trilinos_sparse_matrix.h>
4927 *  
4928 *   #include <deal.II/numerics/vector_tools_common.h>
4929 *  
4930 *   #include <boost/geometry/algorithms/distance.hpp>
4931 *   #include <boost/geometry/index/detail/rtree/utilities/print.hpp>
4932 *   #include <boost/geometry/index/rtree.hpp>
4933 *   #include <boost/geometry/strategies/strategies.hpp>
4934 *  
4935 *   #include <memory>
4936 *  
4937 *   namespace ::PolyUtils::internal
4938 *   {
4939 *   /**
4940 *   * Helper function to compute the position of index @p index in vector @p v.
4941 *   */
4942 *   inline types::global_cell_index
4943 *   get_index(const std::vector<types::global_cell_index> &v,
4944 *   const types::global_cell_index index)
4945 *   {
4946 *   return std::distance(v.begin(), std::find(v.begin(), v.end(), index));
4947 *   }
4948 *  
4949 *   /**
4950 *   * Compute the connectivity graph for locally owned regions of a distributed
4951 *   * triangulation.
4952 *   */
4953 *   template <int dim, int spacedim>
4954 *   void
4955 *   get_face_connectivity_of_cells(
4956 *   const parallel::fullydistributed::Triangulation<dim, spacedim>
4957 *   &triangulation,
4958 *   DynamicSparsityPattern &cell_connectivity,
4959 *   const std::vector<types::global_cell_index> locally_owned_cells)
4960 *   {
4961 *   cell_connectivity.reinit(triangulation.n_locally_owned_active_cells(),
4962 *   triangulation.n_locally_owned_active_cells());
4963 *  
4964 * @endcode
4965 *
4966 * loop over all cells and their neighbors to build the sparsity
4967 * pattern. note that it's a bit hard to enter all the connections when
4968 * a neighbor has children since we would need to find out which of its
4969 * children is adjacent to the current cell. this problem can be omitted
4970 * if we only do something if the neighbor has no children -- in that
4971 * case it is either on the same or a coarser level than we are. in
4972 * return, we have to add entries in both directions for both cells
4973 *
4974 * @code
4975 *   for (const auto &cell : triangulation.active_cell_iterators())
4976 *   {
4977 *   if (cell->is_locally_owned())
4978 *   {
4979 *   const unsigned int index = cell->active_cell_index();
4980 *   cell_connectivity.add(get_index(locally_owned_cells, index),
4981 *   get_index(locally_owned_cells, index));
4982 *   for (auto f : cell->face_indices())
4983 *   if ((cell->at_boundary(f) == false) &&
4984 *   (cell->neighbor(f)->has_children() == false) &&
4985 *   cell->neighbor(f)->is_locally_owned())
4986 *   {
4987 *   const unsigned int other_index =
4988 *   cell->neighbor(f)->active_cell_index();
4989 *  
4990 *   cell_connectivity.add(get_index(locally_owned_cells, index),
4991 *   get_index(locally_owned_cells,
4992 *   other_index));
4993 *   cell_connectivity.add(get_index(locally_owned_cells,
4994 *   other_index),
4995 *   get_index(locally_owned_cells, index));
4996 *   }
4997 *   }
4998 *   }
4999 *   }
5000 *   } // namespace ::PolyUtils::internal
5001 *  
5002 *   namespace ::PolyUtils
5003 *   {
5004 *   template <typename Value,
5005 *   typename Options,
5006 *   typename Translator,
5007 *   typename Box,
5008 *   typename Allocators>
5009 *   struct Rtree_visitor : public boost::geometry::index::detail::rtree::visitor<
5010 *   Value,
5011 *   typename Options::parameters_type,
5012 *   Box,
5013 *   Allocators,
5014 *   typename Options::node_tag,
5015 *   true>::type
5016 *   {
5017 *   inline Rtree_visitor(
5018 *   const Translator &translator,
5019 *   unsigned int target_level,
5020 *   std::vector<std::vector<typename Triangulation<
5021 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>> &boxes,
5022 *   std::vector<std::vector<unsigned int>> &csr);
5023 *  
5024 *   /**
5025 *   * An alias that identifies an InternalNode of the tree.
5026 *   */
5027 *   using InternalNode =
5028 *   typename boost::geometry::index::detail::rtree::internal_node<
5029 *   Value,
5030 *   typename Options::parameters_type,
5031 *   Box,
5032 *   Allocators,
5033 *   typename Options::node_tag>::type;
5034 *  
5035 *   /**
5036 *   * An alias that identifies a Leaf of the tree.
5037 *   */
5038 *   using Leaf = typename boost::geometry::index::detail::rtree::leaf<
5039 *   Value,
5040 *   typename Options::parameters_type,
5041 *   Box,
5042 *   Allocators,
5043 *   typename Options::node_tag>::type;
5044 *  
5045 *   /**
5046 *   * Implements the visitor interface for InternalNode objects. If the node
5047 *   * belongs to the level next to @p target_level, then fill the bounding box
5048 *   * vector for that node.
5049 *   */
5050 *   inline void
5051 *   operator()(const InternalNode &node);
5052 *  
5053 *   /**
5054 *   * Implements the visitor interface for Leaf objects.
5055 *   */
5056 *   inline void
5057 *   operator()(const Leaf &);
5058 *  
5059 *   /**
5060 *   * Translator interface, required by the boost implementation of the rtree.
5061 *   */
5062 *   const Translator &translator;
5063 *  
5064 *   /**
5065 *   * Store the level we are currently visiting.
5066 *   */
5067 *   size_t level;
5068 *  
5069 *   /**
5070 *   * Index used to keep track of the number of different visited nodes during
5071 *   * recursion/
5072 *   */
5073 *   size_t node_counter;
5074 *  
5075 *   size_t next_level_leafs_processed;
5076 *   /**
5077 *   * The level where children are living.
5078 *   * Before: "we want to extract from the RTree object."
5079 *   */
5080 *   const size_t target_level;
5081 *  
5082 *   /**
5083 *   * A reference to the input vector of vector of BoundingBox objects. This
5084 *   * vector v has the following property: v[i] = vector with all
5085 *   * of the BoundingBox bounded by the i-th node of the Rtree.
5086 *   */
5087 *   std::vector<std::vector<typename Triangulation<
5088 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>>
5089 *   &agglomerates;
5090 *  
5091 *   std::vector<std::vector<unsigned int>> &row_ptr;
5092 *   };
5093 *  
5094 *   template <typename Value,
5095 *   typename Options,
5096 *   typename Translator,
5097 *   typename Box,
5098 *   typename Allocators>
5099 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::Rtree_visitor(
5100 *   const Translator &translator,
5101 *   const unsigned int target_level,
5102 *   std::vector<std::vector<typename Triangulation<
5103 *   boost::geometry::dimension<Box>::value>::active_cell_iterator>>
5104 *   &bb_in_boxes,
5105 *   std::vector<std::vector<unsigned int>> &csr)
5106 *   : translator(translator)
5107 *   , level(0)
5108 *   , node_counter(0)
5109 *   , next_level_leafs_processed(0)
5110 *   , target_level(target_level)
5111 *   , agglomerates(bb_in_boxes)
5112 *   , row_ptr(csr)
5113 *   {}
5114 *  
5115 *   template <typename Value,
5116 *   typename Options,
5117 *   typename Translator,
5118 *   typename Box,
5119 *   typename Allocators>
5120 *   void
5121 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::operator()(
5122 *   const Rtree_visitor::InternalNode &node)
5123 *   {
5124 *   using elements_type =
5125 *   typename boost::geometry::index::detail::rtree::elements_type<
5126 *   InternalNode>::type; // pairs of bounding box and pointer to child
5127 * @endcode
5128 *
5129 * node
5130 *
5131 * @code
5132 *   const elements_type &elements =
5133 *   boost::geometry::index::detail::rtree::elements(node);
5134 *  
5135 *   if (level < target_level)
5136 *   {
5137 *   size_t level_backup = level;
5138 *   ++level;
5139 *  
5140 *   for (typename elements_type::const_iterator it = elements.begin();
5141 *   it != elements.end();
5142 *   ++it)
5143 *   {
5144 *   boost::geometry::index::detail::rtree::apply_visitor(*this,
5145 *   *it->second);
5146 *   }
5147 *  
5148 *   level = level_backup;
5149 *   }
5150 *   else if (level == target_level)
5151 *   {
5152 * @endcode
5153 *
5154 * const unsigned int n_children = elements.size();
5155 *
5156 * @code
5157 *   const auto offset = agglomerates.size();
5158 *   agglomerates.resize(offset + 1);
5159 *   row_ptr.resize(row_ptr.size() + 1);
5160 *   next_level_leafs_processed = 0;
5161 *   row_ptr.back().push_back(
5162 *   next_level_leafs_processed); // convention: row_ptr[0]=0
5163 *   size_t level_backup = level;
5164 *  
5165 *   ++level;
5166 *   for (const auto &child : elements)
5167 *   {
5168 *   boost::geometry::index::detail::rtree::apply_visitor(*this,
5169 *   *child.second);
5170 *   }
5171 * @endcode
5172 *
5173 * Done with node number 'node_counter'
5174 *
5175
5176 *
5177 *
5178 * @code
5179 *   ++node_counter; // visited all children of an internal node
5180 *  
5181 *   level = level_backup;
5182 *   }
5183 *   else if (level > target_level)
5184 *   {
5185 * @endcode
5186 *
5187 * Keep visiting until you go to the leafs.
5188 *
5189 * @code
5190 *   size_t level_backup = level;
5191 *  
5192 *   ++level;
5193 *  
5194 *   for (const auto &child : elements)
5195 *   {
5196 *   boost::geometry::index::detail::rtree::apply_visitor(*this,
5197 *   *child.second);
5198 *   }
5199 *   level = level_backup;
5200 *   row_ptr[node_counter].push_back(next_level_leafs_processed);
5201 *   }
5202 *   }
5203 *  
5204 *   template <typename Value,
5205 *   typename Options,
5206 *   typename Translator,
5207 *   typename Box,
5208 *   typename Allocators>
5209 *   void
5210 *   Rtree_visitor<Value, Options, Translator, Box, Allocators>::operator()(
5211 *   const Rtree_visitor::Leaf &leaf)
5212 *   {
5213 *   using elements_type =
5214 *   typename boost::geometry::index::detail::rtree::elements_type<
5215 *   Leaf>::type; // pairs of bounding box and pointer to child node
5216 *   const elements_type &elements =
5217 *   boost::geometry::index::detail::rtree::elements(leaf);
5218 *  
5219 *   for (const auto &it : elements)
5220 *   {
5221 *   agglomerates[node_counter].push_back(it.second);
5222 *   }
5223 *   next_level_leafs_processed += elements.size();
5224 *   }
5225 *  
5226 *   template <typename T>
5227 *   inline constexpr T
5228 *   constexpr_pow(T num, unsigned int pow)
5229 *   {
5230 *   return (pow >= sizeof(unsigned int) * 8) ? 0 :
5231 *   pow == 0 ? 1 :
5232 *   num * constexpr_pow(num, pow - 1);
5233 *   }
5234 *  
5235 *   namespace internal
5236 *   {
5237 *   /**
5238 *   * Same as the public free function with the same name, but storing
5239 *   * explicitly the interpolation matrix and performing interpolation through
5240 *   * matrix-vector product.
5241 *   */
5242 *   template <int dim, int spacedim, typename VectorType>
5243 *   void
5244 *   interpolate_to_fine_grid(
5245 *   const AgglomerationHandler<dim, spacedim> &agglomeration_handler,
5246 *   VectorType &dst,
5247 *   const VectorType &src)
5248 *   {
5249 *   Assert((dim == spacedim), ExcNotImplemented());
5250 *   Assert(
5251 *   dst.size() == 0,
5252 *   ExcMessage(
5253 *   "The destination vector must the empt upon calling this function."));
5254 *  
5255 *   using NumberType = typename VectorType::value_type;
5256 *   constexpr bool is_trilinos_vector =
5257 *   std::is_same_v<VectorType, TrilinosWrappers::MPI::Vector>;
5258 *   using MatrixType = std::conditional_t<is_trilinos_vector,
5259 *   TrilinosWrappers::SparseMatrix,
5260 *   SparseMatrix<NumberType>>;
5261 *  
5262 *   MatrixType interpolation_matrix;
5263 *  
5264 *   [[maybe_unused]]
5265 *   typename std::conditional_t<!is_trilinos_vector, SparsityPattern, void *>
5266 *   sp;
5267 *  
5268 * @endcode
5269 *
5270 * Get some info from the handler
5271 *
5272 * @code
5273 *   const DoFHandler<dim, spacedim> &agglo_dh =
5274 *   agglomeration_handler.agglo_dh;
5275 *  
5276 *   DoFHandler<dim, spacedim> *output_dh =
5277 *   const_cast<DoFHandler<dim, spacedim> *>(
5278 *   &agglomeration_handler.output_dh);
5279 *   const FiniteElement<dim, spacedim> &fe = agglomeration_handler.get_fe();
5280 *   const Mapping<dim> &mapping = agglomeration_handler.get_mapping();
5281 *   const Triangulation<dim, spacedim> &tria =
5282 *   agglomeration_handler.get_triangulation();
5283 *   const auto &bboxes = agglomeration_handler.get_local_bboxes();
5284 *  
5285 *   std::unique_ptr<FiniteElement<dim>> output_fe;
5286 *   if (tria.all_reference_cells_are_hyper_cube())
5287 *   output_fe = std::make_unique<FE_DGQ<dim>>(fe.degree);
5288 *   else if (tria.all_reference_cells_are_simplex())
5289 *   output_fe = std::make_unique<FE_SimplexDGP<dim>>(fe.degree);
5290 *   else
5291 *   AssertThrow(false, ExcNotImplemented());
5292 *  
5293 * @endcode
5294 *
5295 * Setup an auxiliary DoFHandler for output purposes
5296 *
5297 * @code
5298 *   output_dh->reinit(tria);
5299 *   output_dh->distribute_dofs(*output_fe);
5300 *  
5301 *   const IndexSet &locally_owned_dofs = output_dh->locally_owned_dofs();
5302 *   const IndexSet locally_relevant_dofs =
5303 *   DoFTools::extract_locally_relevant_dofs(*output_dh);
5304 *  
5305 *   const IndexSet &locally_owned_dofs_agglo = agglo_dh.locally_owned_dofs();
5306 *  
5307 *   DynamicSparsityPattern dsp(output_dh->n_dofs(),
5308 *   agglo_dh.n_dofs(),
5309 *   locally_relevant_dofs);
5310 *  
5311 *   std::vector<types::global_dof_index> agglo_dof_indices(fe.dofs_per_cell);
5312 *   std::vector<types::global_dof_index> standard_dof_indices(
5313 *   fe.dofs_per_cell);
5314 *   std::vector<types::global_dof_index> output_dof_indices(
5315 *   output_fe->dofs_per_cell);
5316 *  
5317 *   Quadrature<dim> quad(output_fe->get_unit_support_points());
5318 *   FEValues<dim, spacedim> output_fe_values(mapping,
5319 *   *output_fe,
5320 *   quad,
5321 *   update_quadrature_points);
5322 *  
5323 *   for (const auto &cell : agglo_dh.active_cell_iterators())
5324 *   if (cell->is_locally_owned())
5325 *   {
5326 *   if (agglomeration_handler.is_master_cell(cell))
5327 *   {
5328 *   auto slaves = agglomeration_handler.get_slaves_of_idx(
5329 *   cell->active_cell_index());
5330 *   slaves.emplace_back(cell);
5331 *  
5332 *   cell->get_dof_indices(agglo_dof_indices);
5333 *  
5334 *   for (const auto &slave : slaves)
5335 *   {
5336 * @endcode
5337 *
5338 * addd master-slave relationship
5339 *
5340 * @code
5341 *   const auto slave_output =
5342 *   slave->as_dof_handler_iterator(*output_dh);
5343 *   slave_output->get_dof_indices(output_dof_indices);
5344 *   for (const auto row : output_dof_indices)
5345 *   dsp.add_entries(row,
5346 *   agglo_dof_indices.begin(),
5347 *   agglo_dof_indices.end());
5348 *   }
5349 *   }
5350 *   }
5351 *  
5352 *   const auto assemble_interpolation_matrix = [&]() {
5353 *   FullMatrix<NumberType> local_matrix(fe.dofs_per_cell, fe.dofs_per_cell);
5354 *   std::vector<Point<dim>> reference_q_points(fe.dofs_per_cell);
5355 *  
5356 * @endcode
5357 *
5358 * Dummy AffineConstraints, only needed for loc2glb
5359 *
5360 * @code
5361 *   AffineConstraints<NumberType> c;
5362 *   c.close();
5363 *  
5364 *   for (const auto &cell : agglo_dh.active_cell_iterators())
5365 *   if (cell->is_locally_owned())
5366 *   {
5367 *   if (agglomeration_handler.is_master_cell(cell))
5368 *   {
5369 *   auto slaves = agglomeration_handler.get_slaves_of_idx(
5370 *   cell->active_cell_index());
5371 *   slaves.emplace_back(cell);
5372 *  
5373 *   cell->get_dof_indices(agglo_dof_indices);
5374 *  
5375 *   const types::global_cell_index polytope_index =
5376 *   agglomeration_handler.cell_to_polytope_index(cell);
5377 *  
5378 * @endcode
5379 *
5380 * Get the box of this agglomerate.
5381 *
5382 * @code
5383 *   const BoundingBox<dim> &box = bboxes[polytope_index];
5384 *  
5385 *   for (const auto &slave : slaves)
5386 *   {
5387 * @endcode
5388 *
5389 * add master-slave relationship
5390 *
5391 * @code
5392 *   const auto slave_output =
5393 *   slave->as_dof_handler_iterator(*output_dh);
5394 *  
5395 *   slave_output->get_dof_indices(output_dof_indices);
5396 *   output_fe_values.reinit(slave_output);
5397 *  
5398 *   local_matrix = 0.;
5399 *  
5400 *   const auto &q_points =
5401 *   output_fe_values.get_quadrature_points();
5402 *   for (const auto i : output_fe_values.dof_indices())
5403 *   {
5404 *   const auto &p = box.real_to_unit(q_points[i]);
5405 *   for (const auto j : output_fe_values.dof_indices())
5406 *   {
5407 *   local_matrix(i, j) = fe.shape_value(j, p);
5408 *   }
5409 *   }
5410 *   c.distribute_local_to_global(local_matrix,
5411 *   output_dof_indices,
5412 *   agglo_dof_indices,
5413 *   interpolation_matrix);
5414 *   }
5415 *   }
5416 *   }
5417 *   };
5418 *  
5419 *   if constexpr (std::is_same_v<MatrixType, TrilinosWrappers::SparseMatrix>)
5420 *   {
5421 *   const MPI_Comm &communicator = tria.get_mpi_communicator();
5422 *   SparsityTools::distribute_sparsity_pattern(dsp,
5423 *   locally_owned_dofs,
5424 *   communicator,
5425 *   locally_relevant_dofs);
5426 *  
5427 *   interpolation_matrix.reinit(locally_owned_dofs,
5428 *   locally_owned_dofs_agglo,
5429 *   dsp,
5430 *   communicator);
5431 *   dst.reinit(locally_owned_dofs);
5432 *   assemble_interpolation_matrix();
5433 *   }
5434 *   else if constexpr (std::is_same_v<MatrixType, SparseMatrix<NumberType>>)
5435 *   {
5436 *   sp.copy_from(dsp);
5437 *   interpolation_matrix.reinit(sp);
5438 *   dst.reinit(output_dh->n_dofs());
5439 *   assemble_interpolation_matrix();
5440 *   }
5441 *   else
5442 *   {
5443 * @endcode
5444 *
5445 * PETSc, LA::d::v options not implemented.
5446 *
5447 * @code
5448 *   (void)agglomeration_handler;
5449 *   (void)dst;
5450 *   (void)src;
5451 *   AssertThrow(false, ExcNotImplemented());
5452 *   }
5453 *  
5454 * @endcode
5455 *
5456 * If tria is distributed
5457 *
5458 * @code
5459 *   if (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
5460 *   &tria) != nullptr)
5461 *   interpolation_matrix.compress(VectorOperation::add);
5462 *  
5463 * @endcode
5464 *
5465 * Finally, perform the interpolation.
5466 *
5467 * @code
5468 *   interpolation_matrix.vmult(dst, src);
5469 *   }
5470 *   } // namespace internal
5471 *  
5472 *   /**
5473 *   * Given a vector @p src, typically the solution stemming after the
5474 *   * agglomerate problem has been solved, this function interpolates @p src
5475 *   * onto the finer grid and stores the result in vector @p dst. The last
5476 *   * argument @p on_the_fly does not build any interpolation matrix and allows
5477 *   * computing the entries in @p dst in a matrix-free fashion.
5478 *   *
5479 *   * @note Supported parallel types are TrilinosWrappers::SparseMatrix and
5480 *   * TrilinosWrappers::MPI::Vector.
5481 *   */
5482 *   template <int dim, int spacedim, typename VectorType>
5483 *   void
5484 *   interpolate_to_fine_grid(
5485 *   const AgglomerationHandler<dim, spacedim> &agglomeration_handler,
5486 *   VectorType &dst,
5487 *   const VectorType &src,
5488 *   const bool on_the_fly = true)
5489 *   {
5490 *   Assert((dim == spacedim), ExcNotImplemented());
5491 *   Assert(
5492 *   dst.size() == 0,
5493 *   ExcMessage(
5494 *   "The destination vector must the empt upon calling this function."));
5495 *  
5496 *   using NumberType = typename VectorType::value_type;
5497 *   static constexpr bool is_trilinos_vector =
5498 *   std::is_same_v<VectorType, TrilinosWrappers::MPI::Vector>;
5499 *  
5500 *   static constexpr bool is_supported_vector =
5501 *   std::is_same_v<VectorType, Vector<NumberType>> || is_trilinos_vector;
5502 *   static_assert(is_supported_vector);
5503 *  
5504 * @endcode
5505 *
5506 * First, check for an easy return
5507 *
5508 * @code
5509 *   if (on_the_fly == false)
5510 *   {
5511 *   return internal::interpolate_to_fine_grid(agglomeration_handler,
5512 *   dst,
5513 *   src);
5514 *   }
5515 *   else
5516 *   {
5517 * @endcode
5518 *
5519 * otherwise, do not create any matrix
5520 *
5521 * @code
5522 *   if (!agglomeration_handler.used_fe_collection())
5523 *   {
5524 * @endcode
5525 *
5526 * Original version: handle case without hp::FECollection
5527 *
5528 * @code
5529 *   const Triangulation<dim, spacedim> &tria =
5530 *   agglomeration_handler.get_triangulation();
5531 *   const Mapping<dim> &mapping = agglomeration_handler.get_mapping();
5532 *   const FiniteElement<dim, spacedim> &original_fe =
5533 *   agglomeration_handler.get_fe();
5534 *  
5535 * @endcode
5536 *
5537 * We use DGQ (on tensor-product meshes) or DGP (on simplex meshes)
5538 * nodal elements of the same degree as the ones in the
5539 * agglomeration handler to interpolate the solution onto the finer
5540 * grid.
5541 *
5542 * @code
5543 *   std::unique_ptr<FiniteElement<dim>> output_fe;
5544 *   if (tria.all_reference_cells_are_hyper_cube())
5545 *   output_fe = std::make_unique<FE_DGQ<dim>>(original_fe.degree);
5546 *   else if (tria.all_reference_cells_are_simplex())
5547 *   output_fe =
5548 *   std::make_unique<FE_SimplexDGP<dim>>(original_fe.degree);
5549 *   else
5550 *   AssertThrow(false, ExcNotImplemented());
5551 *  
5552 *   DoFHandler<dim> &output_dh =
5553 *   const_cast<DoFHandler<dim> &>(agglomeration_handler.output_dh);
5554 *   output_dh.reinit(tria);
5555 *   output_dh.distribute_dofs(*output_fe);
5556 *  
5557 *   if constexpr (std::is_same_v<VectorType,
5558 *   TrilinosWrappers::MPI::Vector>)
5559 *   {
5560 *   const IndexSet &locally_owned_dofs =
5561 *   output_dh.locally_owned_dofs();
5562 *   dst.reinit(locally_owned_dofs);
5563 *   }
5564 *   else if constexpr (std::is_same_v<VectorType, Vector<NumberType>>)
5565 *   {
5566 *   dst.reinit(output_dh.n_dofs());
5567 *   }
5568 *   else
5569 *   {
5570 * @endcode
5571 *
5572 * PETSc, LA::d::v options not implemented.
5573 *
5574 * @code
5575 *   (void)agglomeration_handler;
5576 *   (void)dst;
5577 *   (void)src;
5578 *   AssertThrow(false, ExcNotImplemented());
5579 *   }
5580 *  
5581 *   const unsigned int dofs_per_cell =
5582 *   agglomeration_handler.n_dofs_per_cell();
5583 *   const unsigned int output_dofs_per_cell =
5584 *   output_fe->n_dofs_per_cell();
5585 *   Quadrature<dim> quad(output_fe->get_unit_support_points());
5586 *   FEValues<dim> output_fe_values(mapping,
5587 *   *output_fe,
5588 *   quad,
5589 *   update_quadrature_points);
5590 *  
5591 *   std::vector<types::global_dof_index> local_dof_indices(
5592 *   dofs_per_cell);
5593 *   std::vector<types::global_dof_index> local_dof_indices_output(
5594 *   output_dofs_per_cell);
5595 *  
5596 *   const auto &bboxes = agglomeration_handler.get_local_bboxes();
5597 *   for (const auto &polytope :
5598 *   agglomeration_handler.polytope_iterators())
5599 *   {
5600 *   if (polytope->is_locally_owned())
5601 *   {
5602 *   polytope->get_dof_indices(local_dof_indices);
5603 *   const BoundingBox<dim> &box = bboxes[polytope->index()];
5604 *  
5605 *   const auto &deal_cells =
5606 *   polytope->get_agglomerate(); // fine deal.II cells
5607 *   for (const auto &cell : deal_cells)
5608 *   {
5609 *   const auto slave_output = cell->as_dof_handler_iterator(
5610 *   agglomeration_handler.output_dh);
5611 *   slave_output->get_dof_indices(local_dof_indices_output);
5612 *   output_fe_values.reinit(slave_output);
5613 *  
5614 *   const auto &qpoints =
5615 *   output_fe_values.get_quadrature_points();
5616 *  
5617 *   for (unsigned int j = 0; j < output_dofs_per_cell; ++j)
5618 *   {
5619 *   const auto &ref_qpoint =
5620 *   box.real_to_unit(qpoints[j]);
5621 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
5622 *   dst(local_dof_indices_output[j]) +=
5623 *   src(local_dof_indices[i]) *
5624 *   original_fe.shape_value(i, ref_qpoint);
5625 *   }
5626 *   }
5627 *   }
5628 *   }
5629 *   }
5630 *   else
5631 *   {
5632 * @endcode
5633 *
5634 * Handle the hp::FECollection case
5635 *
5636 * @code
5637 *   const Triangulation<dim, spacedim> &tria =
5638 *   agglomeration_handler.get_triangulation();
5639 *   const Mapping<dim> &mapping = agglomeration_handler.get_mapping();
5640 *   const hp::FECollection<dim, spacedim> &original_fe_collection =
5641 *   agglomeration_handler.get_fe_collection();
5642 *  
5643 * @endcode
5644 *
5645 * We use DGQ (on tensor-product meshes) or DGP (on simplex meshes)
5646 * nodal elements of the same degree as the ones in the
5647 * agglomeration handler to interpolate the solution onto the finer
5648 * grid.
5649 *
5650 * @code
5651 *   hp::FECollection<dim, spacedim> output_fe_collection;
5652 *  
5653 *   Assert(original_fe_collection[0].n_components() >= 1,
5654 *   ExcMessage("Invalid FE: must have at least one component."));
5655 *   if (original_fe_collection[0].n_components() == 1)
5656 *   {
5657 * @endcode
5658 *
5659 * Scalar case
5660 *
5661 * @code
5662 *   for (unsigned int i = 0; i < original_fe_collection.size(); ++i)
5663 *   {
5664 *   std::unique_ptr<FiniteElement<dim>> output_fe;
5665 *   if (tria.all_reference_cells_are_hyper_cube())
5666 *   output_fe = std::make_unique<FE_DGQ<dim>>(
5667 *   original_fe_collection[i].degree);
5668 *   else if (tria.all_reference_cells_are_simplex())
5669 *   output_fe = std::make_unique<FE_SimplexDGP<dim>>(
5670 *   original_fe_collection[i].degree);
5671 *   else
5672 *   AssertThrow(false, ExcNotImplemented());
5673 *   output_fe_collection.push_back(*output_fe);
5674 *   }
5675 *   }
5676 *   else if (original_fe_collection[0].n_components() > 1)
5677 *   {
5678 * @endcode
5679 *
5680 * System case
5681 *
5682 * @code
5683 *   for (unsigned int i = 0; i < original_fe_collection.size(); ++i)
5684 *   {
5685 *   std::vector<const FiniteElement<dim, spacedim> *>
5686 *   base_elements;
5687 *   std::vector<unsigned int> multiplicities;
5688 *   for (unsigned int b = 0;
5689 *   b < original_fe_collection[i].n_base_elements();
5690 *   ++b)
5691 *   {
5692 *   if (dynamic_cast<const FE_Nothing<dim> *>(
5693 *   &original_fe_collection[i].base_element(b)))
5694 *   base_elements.push_back(
5695 *   new FE_Nothing<dim, spacedim>());
5696 *   else
5697 *   {
5698 *   if (tria.all_reference_cells_are_hyper_cube())
5699 *   base_elements.push_back(new FE_DGQ<dim, spacedim>(
5700 *   original_fe_collection[i]
5701 *   .base_element(b)
5702 *   .degree));
5703 *   else if (tria.all_reference_cells_are_simplex())
5704 *   base_elements.push_back(
5705 *   new FE_SimplexDGP<dim, spacedim>(
5706 *   original_fe_collection[i]
5707 *   .base_element(b)
5708 *   .degree));
5709 *   else
5710 *   AssertThrow(false, ExcNotImplemented());
5711 *   }
5712 *   multiplicities.push_back(
5713 *   original_fe_collection[i].element_multiplicity(b));
5714 *   }
5715 *  
5716 *   FESystem<dim, spacedim> output_fe_system(base_elements,
5717 *   multiplicities);
5718 *   for (const auto *ptr : base_elements)
5719 *   delete ptr;
5720 *   output_fe_collection.push_back(output_fe_system);
5721 *   }
5722 *   }
5723 *  
5724 *   DoFHandler<dim> &output_dh =
5725 *   const_cast<DoFHandler<dim> &>(agglomeration_handler.output_dh);
5726 *   output_dh.reinit(tria);
5727 *   for (const auto &polytope :
5728 *   agglomeration_handler.polytope_iterators())
5729 *   {
5730 *   if (polytope->is_locally_owned())
5731 *   {
5732 *   const auto &deal_cells =
5733 *   polytope->get_agglomerate(); // fine deal.II cells
5734 *   const unsigned int active_fe_idx =
5735 *   polytope->active_fe_index();
5736 *  
5737 *   for (const auto &cell : deal_cells)
5738 *   {
5739 *   const typename DoFHandler<dim>::active_cell_iterator
5740 *   slave_cell_dh_iterator =
5741 *   cell->as_dof_handler_iterator(output_dh);
5742 *   slave_cell_dh_iterator->set_active_fe_index(
5743 *   active_fe_idx);
5744 *   }
5745 *   }
5746 *   }
5747 *   output_dh.distribute_dofs(output_fe_collection);
5748 *  
5749 *   if constexpr (std::is_same_v<VectorType,
5750 *   TrilinosWrappers::MPI::Vector>)
5751 *   {
5752 *   const IndexSet &locally_owned_dofs =
5753 *   output_dh.locally_owned_dofs();
5754 *   dst.reinit(locally_owned_dofs);
5755 *   }
5756 *   else if constexpr (std::is_same_v<VectorType, Vector<NumberType>>)
5757 *   {
5758 *   dst.reinit(output_dh.n_dofs());
5759 *   }
5760 *   else
5761 *   {
5762 * @endcode
5763 *
5764 * PETSc, LA::d::v options not implemented.
5765 *
5766 * @code
5767 *   (void)agglomeration_handler;
5768 *   (void)dst;
5769 *   (void)src;
5770 *   AssertThrow(false, ExcNotImplemented());
5771 *   }
5772 *  
5773 *   const auto &bboxes = agglomeration_handler.get_local_bboxes();
5774 *   for (const auto &polytope :
5775 *   agglomeration_handler.polytope_iterators())
5776 *   {
5777 *   if (polytope->is_locally_owned())
5778 *   {
5779 *   const unsigned int active_fe_idx =
5780 *   polytope->active_fe_index();
5781 *   const unsigned int dofs_per_cell =
5782 *   polytope->get_fe().dofs_per_cell;
5783 *   const unsigned int output_dofs_per_cell =
5784 *   output_fe_collection[active_fe_idx].n_dofs_per_cell();
5785 *   Quadrature<dim> quad(output_fe_collection[active_fe_idx]
5786 *   .get_unit_support_points());
5787 *   FEValues<dim> output_fe_values(
5788 *   mapping,
5789 *   output_fe_collection[active_fe_idx],
5790 *   quad,
5791 *   update_quadrature_points);
5792 *   std::vector<types::global_dof_index> local_dof_indices(
5793 *   dofs_per_cell);
5794 *   std::vector<types::global_dof_index>
5795 *   local_dof_indices_output(output_dofs_per_cell);
5796 *  
5797 *   polytope->get_dof_indices(local_dof_indices);
5798 *   const BoundingBox<dim> &box = bboxes[polytope->index()];
5799 *  
5800 *   const auto &deal_cells =
5801 *   polytope->get_agglomerate(); // fine deal.II cells
5802 *   for (const auto &cell : deal_cells)
5803 *   {
5804 *   const auto slave_output = cell->as_dof_handler_iterator(
5805 *   agglomeration_handler.output_dh);
5806 *   slave_output->get_dof_indices(local_dof_indices_output);
5807 *   output_fe_values.reinit(slave_output);
5808 *  
5809 *   const auto &qpoints =
5810 *   output_fe_values.get_quadrature_points();
5811 *  
5812 *   for (unsigned int j = 0; j < output_dofs_per_cell; ++j)
5813 *   {
5814 *   const unsigned int component_idx_of_this_dof =
5815 *   slave_output->get_fe()
5816 *   .system_to_component_index(j)
5817 *   .first;
5818 *   const auto &ref_qpoint =
5819 *   box.real_to_unit(qpoints[j]);
5820 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
5821 *   dst(local_dof_indices_output[j]) +=
5822 *   src(local_dof_indices[i]) *
5823 *   original_fe_collection[active_fe_idx]
5824 *   .shape_value_component(
5825 *   i, ref_qpoint, component_idx_of_this_dof);
5826 *   }
5827 *   }
5828 *   }
5829 *   }
5830 *   }
5831 *   }
5832 *   }
5833 *  
5834 *   /**
5835 *   * Similar to VectorTools::compute_global_error(), but customized for
5836 *   * polytopic elements. Aside from the solution vector and a reference
5837 *   * function, this function takes in addition a vector @p norms with types
5838 *   * VectorTools::NormType to be computed and later stored in the last
5839 *   * argument @p global_errors.
5840 *   * In case of a parallel vector, the local errors are collected over each
5841 *   * processor and later a classical reduction operation is performed.
5842 *   */
5843 *   template <int dim, typename Number, typename VectorType>
5844 *   void
5845 *   compute_global_error(const AgglomerationHandler<dim> &agglomeration_handler,
5846 *   const VectorType &solution,
5847 *   const Function<dim, Number> &exact_solution,
5848 *   const std::vector<VectorTools::NormType> &norms,
5849 *   std::vector<double> &global_errors)
5850 *   {
5851 *   Assert(solution.size() > 0,
5852 *   ExcNotImplemented(
5853 *   "Solution vector must be non-empty upon calling this function."));
5854 *   Assert(std::any_of(norms.cbegin(),
5855 *   norms.cend(),
5856 *   [](VectorTools::NormType norm_type) {
5857 *   return (norm_type ==
5858 *   VectorTools::NormType::H1_seminorm ||
5859 *   norm_type == VectorTools::NormType::L2_norm);
5860 *   }),
5861 *   ExcMessage("Norm type not supported"));
5862 *   global_errors.resize(norms.size());
5863 *   std::fill(global_errors.begin(), global_errors.end(), 0.);
5864 *  
5865 * @endcode
5866 *
5867 * Vector storing errors local to the current processor.
5868 *
5869 * @code
5870 *   std::vector<double> local_errors(norms.size());
5871 *   std::fill(local_errors.begin(), local_errors.end(), 0.);
5872 *  
5873 * @endcode
5874 *
5875 * Get some info from the handler
5876 *
5877 * @code
5878 *   const unsigned int dofs_per_cell = agglomeration_handler.n_dofs_per_cell();
5879 *  
5880 *   const bool compute_semi_H1 =
5881 *   std::any_of(norms.cbegin(),
5882 *   norms.cend(),
5883 *   [](VectorTools::NormType norm_type) {
5884 *   return norm_type == VectorTools::NormType::H1_seminorm;
5885 *   });
5886 *  
5887 *   std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
5888 *   for (const auto &polytope : agglomeration_handler.polytope_iterators())
5889 *   {
5890 *   if (polytope->is_locally_owned())
5891 *   {
5892 *   const auto &agglo_values = agglomeration_handler.reinit(polytope);
5893 *   polytope->get_dof_indices(local_dof_indices);
5894 *  
5895 *   const auto &q_points = agglo_values.get_quadrature_points();
5896 *   const unsigned int n_qpoints = q_points.size();
5897 *   std::vector<double> analyical_sol_at_qpoints(n_qpoints);
5898 *   exact_solution.value_list(q_points, analyical_sol_at_qpoints);
5899 *   std::vector<Tensor<1, dim>> grad_analyical_sol_at_qpoints(
5900 *   n_qpoints);
5901 *  
5902 *   if (compute_semi_H1)
5903 *   exact_solution.gradient_list(q_points,
5904 *   grad_analyical_sol_at_qpoints);
5905 *  
5906 *   for (unsigned int q_index : agglo_values.quadrature_point_indices())
5907 *   {
5908 *   double solution_at_qpoint = 0.;
5909 *   Tensor<1, dim> grad_solution_at_qpoint;
5910 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
5911 *   {
5912 *   solution_at_qpoint += solution(local_dof_indices[i]) *
5913 *   agglo_values.shape_value(i, q_index);
5914 *  
5915 *   if (compute_semi_H1)
5916 *   grad_solution_at_qpoint +=
5917 *   solution(local_dof_indices[i]) *
5918 *   agglo_values.shape_grad(i, q_index);
5919 *   }
5920 * @endcode
5921 *
5922 * L2
5923 *
5924 * @code
5925 *   local_errors[0] += std::pow((analyical_sol_at_qpoints[q_index] -
5926 *   solution_at_qpoint),
5927 *   2) *
5928 *   agglo_values.JxW(q_index);
5929 *  
5930 * @endcode
5931 *
5932 * H1 seminorm
5933 *
5934 * @code
5935 *   if (compute_semi_H1)
5936 *   for (unsigned int d = 0; d < dim; ++d)
5937 *   local_errors[1] +=
5938 *   std::pow((grad_analyical_sol_at_qpoints[q_index][d] -
5939 *   grad_solution_at_qpoint[d]),
5940 *   2) *
5941 *   agglo_values.JxW(q_index);
5942 *   }
5943 *   }
5944 *   }
5945 *  
5946 * @endcode
5947 *
5948 * Perform reduction and take sqrt of each error
5949 *
5950 * @code
5951 *   global_errors[0] = Utilities::MPI::reduce<double>(
5952 *   local_errors[0],
5953 *   agglomeration_handler.get_triangulation().get_mpi_communicator(),
5954 *   [](const double a, const double b) { return a + b; });
5955 *  
5956 *   global_errors[0] = std::sqrt(global_errors[0]);
5957 *  
5958 *   if (compute_semi_H1)
5959 *   {
5960 *   global_errors[1] = Utilities::MPI::reduce<double>(
5961 *   local_errors[1],
5962 *   agglomeration_handler.get_triangulation().get_mpi_communicator(),
5963 *   [](const double a, const double b) { return a + b; });
5964 *   global_errors[1] = std::sqrt(global_errors[1]);
5965 *   }
5966 *   }
5967 *  
5968 *   /**
5969 *   * Utility function that builds the multilevel hierarchy from the tree level
5970 *   * @p starting_level. This function fills the vector of
5971 *   * @p AgglomerationHandlers objects by distributing degrees of freedom on
5972 *   * each level of the hierarchy. It returns the total number of levels in the
5973 *   * hierarchy.
5974 *   */
5975 *   template <int dim>
5976 *   unsigned int
5977 *   construct_agglomerated_levels(
5978 *   const Triangulation<dim> &tria,
5979 *   std::vector<std::unique_ptr<AgglomerationHandler<dim>>>
5980 *   &agglomeration_handlers,
5981 *   const FE_DGQ<dim> &fe_dg,
5982 *   const Mapping<dim> &mapping,
5983 *   const unsigned int starting_tree_level)
5984 *   {
5985 *   const auto parallel_tria =
5986 *   dynamic_cast<const parallel::TriangulationBase<dim> *>(&tria);
5987 *  
5988 *   GridTools::Cache<dim> cached_tria(tria);
5989 *   Assert(parallel_tria->n_active_cells() > 0, ExcInternalError());
5990 *  
5991 *   const MPI_Comm comm = parallel_tria->get_mpi_communicator();
5992 *   ConditionalOStream pcout(std::cout,
5993 *   (Utilities::MPI::this_mpi_process(comm) == 0));
5994 *  
5995 * @endcode
5996 *
5997 * Start building R-tree
5998 *
5999 * @code
6000 *   namespace bgi = boost::geometry::index;
6001 *   static constexpr unsigned int max_elem_per_node =
6002 *   constexpr_pow(2, dim); // 2^dim
6003 *   std::vector<std::pair<BoundingBox<dim>,
6004 *   typename Triangulation<dim>::active_cell_iterator>>
6005 *   boxes(parallel_tria->n_locally_owned_active_cells());
6006 *   unsigned int i = 0;
6007 *   for (const auto &cell : parallel_tria->active_cell_iterators())
6008 *   if (cell->is_locally_owned())
6009 *   boxes[i++] = std::make_pair(mapping.get_bounding_box(cell), cell);
6010 *  
6011 *   auto tree = pack_rtree<bgi::rstar<max_elem_per_node>>(boxes);
6012 *   Assert(n_levels(tree) >= 2, ExcMessage("At least two levels are needed."));
6013 *   pcout << "Total number of available levels: " << n_levels(tree)
6014 *   << std::endl;
6015 *  
6016 *   pcout << "Starting level: " << starting_tree_level << std::endl;
6017 *   const unsigned int total_tree_levels =
6018 *   n_levels(tree) - starting_tree_level + 1;
6019 *  
6020 * @endcode
6021 *
6022 * Resize the agglomeration handlers to the right size
6023 *
6024
6025 *
6026 *
6027 * @code
6028 *   agglomeration_handlers.resize(total_tree_levels);
6029 * @endcode
6030 *
6031 * Loop through the available levels and set AgglomerationHandlers up.
6032 *
6033 * @code
6034 *   for (unsigned int extraction_level = starting_tree_level;
6035 *   extraction_level <= n_levels(tree);
6036 *   ++extraction_level)
6037 *   {
6038 *   agglomeration_handlers[extraction_level - starting_tree_level] =
6039 *   std::make_unique<AgglomerationHandler<dim>>(cached_tria);
6040 *   CellsAgglomerator<dim, decltype(tree)> agglomerator{tree,
6041 *   extraction_level};
6042 *   const auto agglomerates = agglomerator.extract_agglomerates();
6043 *   agglomeration_handlers[extraction_level - starting_tree_level]
6044 *   ->connect_hierarchy(agglomerator);
6045 *  
6046 * @endcode
6047 *
6048 * Flag elements for agglomeration
6049 *
6050 * @code
6051 *   unsigned int agglo_index = 0;
6052 *   for (unsigned int i = 0; i < agglomerates.size(); ++i)
6053 *   {
6054 *   const auto &agglo = agglomerates[i]; // i-th agglomerate
6055 *   for (const auto &el : agglo)
6056 *   {
6057 *   el->set_material_id(agglo_index);
6058 *   }
6059 *   ++agglo_index;
6060 *   }
6061 *  
6062 *   const unsigned int n_local_agglomerates = agglo_index;
6063 *   unsigned int total_agglomerates =
6064 *   Utilities::MPI::sum(n_local_agglomerates, comm);
6065 *   pcout << "Total agglomerates per (tree) level: " << extraction_level
6066 *   << ": " << total_agglomerates << std::endl;
6067 *  
6068 * @endcode
6069 *
6070 * Now, perform agglomeration within each locally owned partition
6071 *
6072 * @code
6073 *   std::vector<
6074 *   std::vector<typename Triangulation<dim>::active_cell_iterator>>
6075 *   cells_per_subdomain(n_local_agglomerates);
6076 *   for (const auto &cell : parallel_tria->active_cell_iterators())
6077 *   if (cell->is_locally_owned())
6078 *   cells_per_subdomain[cell->material_id()].push_back(cell);
6079 *  
6080 * @endcode
6081 *
6082 * For every subdomain, agglomerate elements together
6083 *
6084 * @code
6085 *   for (std::size_t i = 0; i < cells_per_subdomain.size(); ++i)
6086 *   agglomeration_handlers[extraction_level - starting_tree_level]
6087 *   ->define_agglomerate(cells_per_subdomain[i]);
6088 *  
6089 *   agglomeration_handlers[extraction_level - starting_tree_level]
6090 *   ->initialize_fe_values(QGauss<dim>(fe_dg.degree + 1),
6091 *   update_values | update_gradients |
6092 *   update_JxW_values | update_quadrature_points,
6093 *   QGauss<dim - 1>(fe_dg.degree + 1),
6094 *   update_JxW_values);
6095 *   agglomeration_handlers[extraction_level - starting_tree_level]
6096 *   ->distribute_agglomerated_dofs(fe_dg);
6097 *   }
6098 *  
6099 *   return total_tree_levels;
6100 *   }
6101 *  
6102 *   /**
6103 *   * Utility to compute jump terms when the interface is locally owned, i.e.
6104 *   * both elements are locally owned.
6105 *   */
6106 *   template <int dim>
6107 *   void
6108 *   assemble_local_jumps_and_averages(FullMatrix<double> &M11,
6109 *   FullMatrix<double> &M12,
6110 *   FullMatrix<double> &M21,
6111 *   FullMatrix<double> &M22,
6112 *   const FEValuesBase<dim> &fe_faces0,
6113 *   const FEValuesBase<dim> &fe_faces1,
6114 *   const double penalty_constant,
6115 *   const double h_f)
6116 *   {
6117 *   const std::vector<Tensor<1, dim>> &normals = fe_faces0.get_normal_vectors();
6118 *   const unsigned int dofs_per_cell =
6119 *   M11.m(); // size of local matrices equals the #DoFs
6120 *   for (unsigned int q_index : fe_faces0.quadrature_point_indices())
6121 *   {
6122 *   const Tensor<1, dim> &normal = normals[q_index];
6123 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6124 *   {
6125 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6126 *   {
6127 *   M11(i, j) += (-0.5 * fe_faces0.shape_grad(i, q_index) * normal *
6128 *   fe_faces0.shape_value(j, q_index) -
6129 *   0.5 * fe_faces0.shape_grad(j, q_index) * normal *
6130 *   fe_faces0.shape_value(i, q_index) +
6131 *   (penalty_constant / h_f) *
6132 *   fe_faces0.shape_value(i, q_index) *
6133 *   fe_faces0.shape_value(j, q_index)) *
6134 *   fe_faces0.JxW(q_index);
6135 *   M12(i, j) += (0.5 * fe_faces0.shape_grad(i, q_index) * normal *
6136 *   fe_faces1.shape_value(j, q_index) -
6137 *   0.5 * fe_faces1.shape_grad(j, q_index) * normal *
6138 *   fe_faces0.shape_value(i, q_index) -
6139 *   (penalty_constant / h_f) *
6140 *   fe_faces0.shape_value(i, q_index) *
6141 *   fe_faces1.shape_value(j, q_index)) *
6142 *   fe_faces1.JxW(q_index);
6143 *   M21(i, j) += (-0.5 * fe_faces1.shape_grad(i, q_index) * normal *
6144 *   fe_faces0.shape_value(j, q_index) +
6145 *   0.5 * fe_faces0.shape_grad(j, q_index) * normal *
6146 *   fe_faces1.shape_value(i, q_index) -
6147 *   (penalty_constant / h_f) *
6148 *   fe_faces1.shape_value(i, q_index) *
6149 *   fe_faces0.shape_value(j, q_index)) *
6150 *   fe_faces1.JxW(q_index);
6151 *   M22(i, j) += (0.5 * fe_faces1.shape_grad(i, q_index) * normal *
6152 *   fe_faces1.shape_value(j, q_index) +
6153 *   0.5 * fe_faces1.shape_grad(j, q_index) * normal *
6154 *   fe_faces1.shape_value(i, q_index) +
6155 *   (penalty_constant / h_f) *
6156 *   fe_faces1.shape_value(i, q_index) *
6157 *   fe_faces1.shape_value(j, q_index)) *
6158 *   fe_faces1.JxW(q_index);
6159 *   }
6160 *   }
6161 *   }
6162 *   }
6163 *   /**
6164 *   * Same as above, but for a ghosted neighbor.
6165 *   */
6166 *   template <int dim>
6167 *   void
6168 *   assemble_local_jumps_and_averages_ghost(
6169 *   FullMatrix<double> &M11,
6170 *   FullMatrix<double> &M12,
6171 *   FullMatrix<double> &M21,
6172 *   FullMatrix<double> &M22,
6173 *   const FEValuesBase<dim> &fe_faces0,
6174 *   const std::vector<std::vector<double>> &recv_values,
6175 *   const std::vector<std::vector<Tensor<1, dim>>> &recv_gradients,
6176 *   const std::vector<double> &recv_jxws,
6177 *   const double penalty_constant,
6178 *   const double h_f)
6179 *   {
6180 *   Assert(
6181 *   (recv_values.size() > 0 && recv_gradients.size() && recv_jxws.size()),
6182 *   ExcMessage("Not possible to assemble jumps and averages at a ghosted "
6183 *   "interface."));
6184 *   const unsigned int dofs_per_cell = M11.m();
6185 *   const std::vector<Tensor<1, dim>> &normals = fe_faces0.get_normal_vectors();
6186 *   for (unsigned int q_index : fe_faces0.quadrature_point_indices())
6187 *   {
6188 *   const Tensor<1, dim> &normal = normals[q_index];
6189 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6190 *   {
6191 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6192 *   {
6193 *   M11(i, j) += (-0.5 * fe_faces0.shape_grad(i, q_index) * normal *
6194 *   fe_faces0.shape_value(j, q_index) -
6195 *   0.5 * fe_faces0.shape_grad(j, q_index) * normal *
6196 *   fe_faces0.shape_value(i, q_index) +
6197 *   (penalty_constant / h_f) *
6198 *   fe_faces0.shape_value(i, q_index) *
6199 *   fe_faces0.shape_value(j, q_index)) *
6200 *   fe_faces0.JxW(q_index);
6201 *   M12(i, j) += (0.5 * fe_faces0.shape_grad(i, q_index) * normal *
6202 *   recv_values[j][q_index] -
6203 *   0.5 * recv_gradients[j][q_index] * normal *
6204 *   fe_faces0.shape_value(i, q_index) -
6205 *   (penalty_constant / h_f) *
6206 *   fe_faces0.shape_value(i, q_index) *
6207 *   recv_values[j][q_index]) *
6208 *   recv_jxws[q_index];
6209 *   M21(i, j) +=
6210 *   (-0.5 * recv_gradients[i][q_index] * normal *
6211 *   fe_faces0.shape_value(j, q_index) +
6212 *   0.5 * fe_faces0.shape_grad(j, q_index) * normal *
6213 *   recv_values[i][q_index] -
6214 *   (penalty_constant / h_f) * recv_values[i][q_index] *
6215 *   fe_faces0.shape_value(j, q_index)) *
6216 *   recv_jxws[q_index];
6217 *   M22(i, j) +=
6218 *   (0.5 * recv_gradients[i][q_index] * normal *
6219 *   recv_values[j][q_index] +
6220 *   0.5 * recv_gradients[j][q_index] * normal *
6221 *   recv_values[i][q_index] +
6222 *   (penalty_constant / h_f) * recv_values[i][q_index] *
6223 *   recv_values[j][q_index]) *
6224 *   recv_jxws[q_index];
6225 *   }
6226 *   }
6227 *   }
6228 *   }
6229 *  
6230 *   /**
6231 *   * Utility function to assemble the SIPDG Laplace matrix.
6232 *   * @note Supported matrix types are Trilinos types and native SparseMatrix
6233 *   * objects provided by deal.II.
6234 *   */
6235 *   template <int dim, typename MatrixType>
6236 *   void
6237 *   assemble_dg_matrix(MatrixType &system_matrix,
6238 *   const FiniteElement<dim> &fe_dg,
6239 *   const AgglomerationHandler<dim> &ah)
6240 *   {
6241 *   static_assert(
6242 *   (std::is_same_v<MatrixType, TrilinosWrappers::SparseMatrix> ||
6243 *   std::is_same_v<MatrixType,
6244 *   SparseMatrix<typename MatrixType::value_type>>));
6245 *  
6246 *   Assert((dynamic_cast<const FE_DGQ<dim> *>(&fe_dg) ||
6247 *   dynamic_cast<const FE_DGP<dim> *>(&fe_dg) ||
6248 *   dynamic_cast<const FE_SimplexDGP<dim> *>(&fe_dg)),
6249 *   ExcMessage("FE type not supported."));
6250 *  
6251 *   AffineConstraints constraints;
6252 *   constraints.close();
6253 *   const double penalty_constant =
6254 *   10 * (fe_dg.degree + dim) * (fe_dg.degree + 1);
6255 *   TrilinosWrappers::SparsityPattern dsp;
6256 *   const_cast<AgglomerationHandler<dim> &>(ah)
6257 *   .create_agglomeration_sparsity_pattern(dsp);
6258 *   system_matrix.reinit(dsp);
6259 *   const unsigned int dofs_per_cell = fe_dg.n_dofs_per_cell();
6260 *   FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
6261 *   FullMatrix<double> M11(dofs_per_cell, dofs_per_cell);
6262 *   FullMatrix<double> M12(dofs_per_cell, dofs_per_cell);
6263 *   FullMatrix<double> M21(dofs_per_cell, dofs_per_cell);
6264 *   FullMatrix<double> M22(dofs_per_cell, dofs_per_cell);
6265 *   std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
6266 *   std::vector<types::global_dof_index> local_dof_indices_neighbor(
6267 *   dofs_per_cell);
6268 *  
6269 *   for (const auto &polytope : ah.polytope_iterators())
6270 *   {
6271 *   if (polytope->is_locally_owned())
6272 *   {
6273 *   cell_matrix = 0.;
6274 *   const auto &agglo_values = ah.reinit(polytope);
6275 *   for (unsigned int q_index : agglo_values.quadrature_point_indices())
6276 *   {
6277 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6278 *   {
6279 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6280 *   {
6281 *   cell_matrix(i, j) +=
6282 *   agglo_values.shape_grad(i, q_index) *
6283 *   agglo_values.shape_grad(j, q_index) *
6284 *   agglo_values.JxW(q_index);
6285 *   }
6286 *   }
6287 *   }
6288 * @endcode
6289 *
6290 * get volumetric DoFs
6291 *
6292 * @code
6293 *   polytope->get_dof_indices(local_dof_indices);
6294 * @endcode
6295 *
6296 * Assemble face terms
6297 *
6298 * @code
6299 *   unsigned int n_faces = polytope->n_faces();
6300 *   const double h_f = polytope->diameter();
6301 *   for (unsigned int f = 0; f < n_faces; ++f)
6302 *   {
6303 *   if (polytope->at_boundary(f))
6304 *   {
6305 * @endcode
6306 *
6307 * Get normal vectors seen from each agglomeration.
6308 *
6309 * @code
6310 *   const auto &fe_face = ah.reinit(polytope, f);
6311 *   const auto &normals = fe_face.get_normal_vectors();
6312 *   for (unsigned int q_index :
6313 *   fe_face.quadrature_point_indices())
6314 *   {
6315 *   const Tensor<1, dim> &normal = normals[q_index];
6316 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6317 *   {
6318 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6319 *   {
6320 *   cell_matrix(i, j) +=
6321 *   (-fe_face.shape_value(i, q_index) *
6322 *   fe_face.shape_grad(j, q_index) * normal -
6323 *   fe_face.shape_grad(i, q_index) * normal *
6324 *   fe_face.shape_value(j, q_index) +
6325 *   (penalty_constant / h_f) *
6326 *   fe_face.shape_value(i, q_index) *
6327 *   fe_face.shape_value(j, q_index)) *
6328 *   fe_face.JxW(q_index);
6329 *   }
6330 *   }
6331 *   }
6332 *   }
6333 *   else
6334 *   {
6335 *   const auto &neigh_polytope = polytope->neighbor(f);
6336 *   if (polytope->id() < neigh_polytope->id())
6337 *   {
6338 *   unsigned int nofn =
6339 *   polytope->neighbor_of_agglomerated_neighbor(f);
6340 *   Assert(neigh_polytope->neighbor(nofn)->id() ==
6341 *   polytope->id(),
6342 *   ExcMessage("Mismatch."));
6343 *   const auto &fe_faces = ah.reinit_interface(
6344 *   polytope, neigh_polytope, f, nofn);
6345 *   const auto &fe_faces0 = fe_faces.first;
6346 *   if (neigh_polytope->is_locally_owned())
6347 *   {
6348 * @endcode
6349 *
6350 * use both fevalues
6351 *
6352 * @code
6353 *   const auto &fe_faces1 = fe_faces.second;
6354 *   M11 = 0.;
6355 *   M12 = 0.;
6356 *   M21 = 0.;
6357 *   M22 = 0.;
6358 *   assemble_local_jumps_and_averages(M11,
6359 *   M12,
6360 *   M21,
6361 *   M22,
6362 *   fe_faces0,
6363 *   fe_faces1,
6364 *   penalty_constant,
6365 *   h_f);
6366 * @endcode
6367 *
6368 * distribute DoFs accordingly
6369 * fluxes
6370 *
6371 * @code
6372 *   neigh_polytope->get_dof_indices(
6373 *   local_dof_indices_neighbor);
6374 *   constraints.distribute_local_to_global(
6375 *   M11, local_dof_indices, system_matrix);
6376 *   constraints.distribute_local_to_global(
6377 *   M12,
6378 *   local_dof_indices,
6379 *   local_dof_indices_neighbor,
6380 *   system_matrix);
6381 *   constraints.distribute_local_to_global(
6382 *   M21,
6383 *   local_dof_indices_neighbor,
6384 *   local_dof_indices,
6385 *   system_matrix);
6386 *   constraints.distribute_local_to_global(
6387 *   M22, local_dof_indices_neighbor, system_matrix);
6388 *   }
6389 *   else
6390 *   {
6391 * @endcode
6392 *
6393 * neigh polytope is ghosted, so retrieve necessary
6394 * metadata.
6395 *
6396 * @code
6397 *   types::subdomain_id neigh_rank =
6398 *   neigh_polytope->subdomain_id();
6399 *   const auto &recv_jxws =
6400 *   ah.recv_jxws.at(neigh_rank)
6401 *   .at({neigh_polytope->id(), nofn});
6402 *   const auto &recv_values =
6403 *   ah.recv_values.at(neigh_rank)
6404 *   .at({neigh_polytope->id(), nofn});
6405 *   const auto &recv_gradients =
6406 *   ah.recv_gradients.at(neigh_rank)
6407 *   .at({neigh_polytope->id(), nofn});
6408 *   M11 = 0.;
6409 *   M12 = 0.;
6410 *   M21 = 0.;
6411 *   M22 = 0.;
6412 * @endcode
6413 *
6414 * there's no FEFaceValues on the other side (it's
6415 * ghosted), so we just pass the actual data we have
6416 * recevied from the neighboring ghosted polytope
6417 *
6418 * @code
6419 *   assemble_local_jumps_and_averages_ghost(
6420 *   M11,
6421 *   M12,
6422 *   M21,
6423 *   M22,
6424 *   fe_faces0,
6425 *   recv_values,
6426 *   recv_gradients,
6427 *   recv_jxws,
6428 *   penalty_constant,
6429 *   h_f);
6430 * @endcode
6431 *
6432 * distribute DoFs accordingly
6433 * fluxes
6434 *
6435 * @code
6436 *   neigh_polytope->get_dof_indices(
6437 *   local_dof_indices_neighbor);
6438 *   constraints.distribute_local_to_global(
6439 *   M11, local_dof_indices, system_matrix);
6440 *   constraints.distribute_local_to_global(
6441 *   M12,
6442 *   local_dof_indices,
6443 *   local_dof_indices_neighbor,
6444 *   system_matrix);
6445 *   constraints.distribute_local_to_global(
6446 *   M21,
6447 *   local_dof_indices_neighbor,
6448 *   local_dof_indices,
6449 *   system_matrix);
6450 *   constraints.distribute_local_to_global(
6451 *   M22, local_dof_indices_neighbor, system_matrix);
6452 *   } // ghosted polytope case
6453 *   } // only once
6454 *   } // internal face
6455 *   } // face loop
6456 *   constraints.distribute_local_to_global(cell_matrix,
6457 *   local_dof_indices,
6458 *   system_matrix);
6459 *   } // locally owned polytopes
6460 *   }
6461 *   system_matrix.compress(VectorOperation::add);
6462 *   }
6463 *  
6464 *   /**
6465 *   * Compute SIPDG matrix as well as rhs vector.
6466 *   * @note Hardcoded for f=1 and simplex elements.
6467 *   * TODO: Pass Function object for boundary conditions and forcing term.
6468 *   */
6469 *   template <int dim, typename MatrixType, typename VectorType>
6470 *   void
6471 *   assemble_dg_matrix_on_standard_mesh(MatrixType &system_matrix,
6472 *   VectorType &system_rhs,
6473 *   const Mapping<dim> &mapping,
6474 *   const FiniteElement<dim> &fe_dg,
6475 *   const DoFHandler<dim> &dof_handler)
6476 *   {
6477 *   static_assert(
6478 *   (std::is_same_v<MatrixType, TrilinosWrappers::SparseMatrix> ||
6479 *   std::is_same_v<MatrixType,
6480 *   SparseMatrix<typename MatrixType::value_type>>));
6481 *  
6482 *   Assert((dynamic_cast<const FE_SimplexDGP<dim> *>(&fe_dg) != nullptr),
6483 *   ExcNotImplemented(
6484 *   "Implemented only for simplex meshes for the time being."));
6485 *  
6486 *   Assert(dof_handler.get_triangulation().all_reference_cells_are_simplex(),
6487 *   ExcNotImplemented());
6488 *  
6489 *   const double penalty_constant = .5 * fe_dg.degree * (fe_dg.degree + 1);
6490 *   AffineConstraints<typename MatrixType::value_type> constraints;
6491 *   constraints.close();
6492 *  
6493 *   const IndexSet &locally_owned_dofs = dof_handler.locally_owned_dofs();
6494 *   const IndexSet locally_relevant_dofs =
6495 *   DoFTools::extract_locally_relevant_dofs(dof_handler);
6496 *  
6497 *   DynamicSparsityPattern dsp(locally_relevant_dofs);
6498 *   DoFTools::make_flux_sparsity_pattern(dof_handler, dsp);
6499 *   SparsityTools::distribute_sparsity_pattern(dsp,
6500 *   dof_handler.locally_owned_dofs(),
6501 *   dof_handler.get_communicator(),
6502 *   locally_relevant_dofs);
6503 *  
6504 *   system_matrix.reinit(locally_owned_dofs,
6505 *   locally_owned_dofs,
6506 *   dsp,
6507 *   dof_handler.get_communicator());
6508 *  
6509 *   system_rhs.reinit(locally_owned_dofs, dof_handler.get_communicator());
6510 *  
6511 *   const unsigned int quadrature_degree = fe_dg.degree + 1;
6512 *   FEFaceValues<dim> fe_faces0(mapping,
6513 *   fe_dg,
6514 *   QGaussSimplex<dim - 1>(quadrature_degree),
6515 *   update_values | update_JxW_values |
6516 *   update_gradients | update_quadrature_points |
6517 *   update_normal_vectors);
6518 *  
6519 *   FEValues<dim> fe_values(mapping,
6520 *   fe_dg,
6521 *   QGaussSimplex<dim>(quadrature_degree),
6522 *   update_values | update_JxW_values |
6523 *   update_gradients | update_quadrature_points);
6524 *  
6525 *   FEFaceValues<dim> fe_faces1(mapping,
6526 *   fe_dg,
6527 *   QGaussSimplex<dim - 1>(quadrature_degree),
6528 *   update_values | update_JxW_values |
6529 *   update_gradients | update_quadrature_points |
6530 *   update_normal_vectors);
6531 *   const unsigned int dofs_per_cell = fe_dg.n_dofs_per_cell();
6532 *  
6533 *   FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
6534 *   Vector<double> cell_rhs(dofs_per_cell);
6535 *  
6536 *   FullMatrix<double> M11(dofs_per_cell, dofs_per_cell);
6537 *   FullMatrix<double> M12(dofs_per_cell, dofs_per_cell);
6538 *   FullMatrix<double> M21(dofs_per_cell, dofs_per_cell);
6539 *   FullMatrix<double> M22(dofs_per_cell, dofs_per_cell);
6540 *  
6541 *   std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
6542 *  
6543 * @endcode
6544 *
6545 * Loop over standard deal.II cells
6546 *
6547 * @code
6548 *   for (const auto &cell : dof_handler.active_cell_iterators())
6549 *   {
6550 *   if (cell->is_locally_owned())
6551 *   {
6552 *   cell_matrix = 0.;
6553 *   cell_rhs = 0.;
6554 *  
6555 *   fe_values.reinit(cell);
6556 *  
6557 * @endcode
6558 *
6559 * const auto &q_points = fe_values.get_quadrature_points();
6560 * const unsigned int n_qpoints = q_points.size();
6561 *
6562
6563 *
6564 *
6565 * @code
6566 *   for (unsigned int q_index : fe_values.quadrature_point_indices())
6567 *   {
6568 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6569 *   {
6570 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6571 *   {
6572 *   cell_matrix(i, j) += fe_values.shape_grad(i, q_index) *
6573 *   fe_values.shape_grad(j, q_index) *
6574 *   fe_values.JxW(q_index);
6575 *   }
6576 *   cell_rhs(i) +=
6577 *   fe_values.shape_value(i, q_index) * 1. *
6578 *   fe_values.JxW(q_index); // TODO: pass functional
6579 *   }
6580 *   }
6581 *  
6582 * @endcode
6583 *
6584 * distribute volumetric DoFs
6585 *
6586 * @code
6587 *   cell->get_dof_indices(local_dof_indices);
6588 *   double hf = 0.;
6589 *   for (const auto f : cell->face_indices())
6590 *   {
6591 *   const double extent1 =
6592 *   cell->measure() / cell->face(f)->measure();
6593 *  
6594 *   if (cell->face(f)->at_boundary())
6595 *   {
6596 *   hf = (1. / extent1 + 1. / extent1);
6597 *   fe_faces0.reinit(cell, f);
6598 *  
6599 *   const auto &normals = fe_faces0.get_normal_vectors();
6600 *   for (unsigned int q_index :
6601 *   fe_faces0.quadrature_point_indices())
6602 *   {
6603 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6604 *   {
6605 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6606 *   {
6607 *   cell_matrix(i, j) +=
6608 *   (-fe_faces0.shape_value(i, q_index) *
6609 *   fe_faces0.shape_grad(j, q_index) *
6610 *   normals[q_index] -
6611 *   fe_faces0.shape_grad(i, q_index) *
6612 *   normals[q_index] *
6613 *   fe_faces0.shape_value(j, q_index) +
6614 *   (penalty_constant * hf) *
6615 *   fe_faces0.shape_value(i, q_index) *
6616 *   fe_faces0.shape_value(j, q_index)) *
6617 *   fe_faces0.JxW(q_index);
6618 *   }
6619 *   cell_rhs(i) +=
6620 *   0.; // TODO: add bdary conditions functional
6621 *   }
6622 *   }
6623 *   }
6624 *   else
6625 *   {
6626 *   const auto &neigh_cell = cell->neighbor(f);
6627 *   if (cell->global_active_cell_index() <
6628 *   neigh_cell->global_active_cell_index())
6629 *   {
6630 *   const double extent2 =
6631 *   neigh_cell->measure() /
6632 *   neigh_cell->face(cell->neighbor_of_neighbor(f))
6633 *   ->measure();
6634 *   hf = (1. / extent1 + 1. / extent2);
6635 *   fe_faces0.reinit(cell, f);
6636 *   fe_faces1.reinit(neigh_cell,
6637 *   cell->neighbor_of_neighbor(f));
6638 *  
6639 *   std::vector<types::global_dof_index>
6640 *   local_dof_indices_neighbor(dofs_per_cell);
6641 *  
6642 *   M11 = 0.;
6643 *   M12 = 0.;
6644 *   M21 = 0.;
6645 *   M22 = 0.;
6646 *  
6647 *   const auto &normals = fe_faces0.get_normal_vectors();
6648 * @endcode
6649 *
6650 * M11
6651 *
6652 * @code
6653 *   for (unsigned int q_index :
6654 *   fe_faces0.quadrature_point_indices())
6655 *   {
6656 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
6657 *   {
6658 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
6659 *   {
6660 *   M11(i, j) +=
6661 *   (-0.5 * fe_faces0.shape_grad(i, q_index) *
6662 *   normals[q_index] *
6663 *   fe_faces0.shape_value(j, q_index) -
6664 *   0.5 * fe_faces0.shape_grad(j, q_index) *
6665 *   normals[q_index] *
6666 *   fe_faces0.shape_value(i, q_index) +
6667 *   (penalty_constant * hf) *
6668 *   fe_faces0.shape_value(i, q_index) *
6669 *   fe_faces0.shape_value(j, q_index)) *
6670 *   fe_faces0.JxW(q_index);
6671 *  
6672 *   M12(i, j) +=
6673 *   (0.5 * fe_faces0.shape_grad(i, q_index) *
6674 *   normals[q_index] *
6675 *   fe_faces1.shape_value(j, q_index) -
6676 *   0.5 * fe_faces1.shape_grad(j, q_index) *
6677 *   normals[q_index] *
6678 *   fe_faces0.shape_value(i, q_index) -
6679 *   (penalty_constant * hf) *
6680 *   fe_faces0.shape_value(i, q_index) *
6681 *   fe_faces1.shape_value(j, q_index)) *
6682 *   fe_faces1.JxW(q_index);
6683 *  
6684 * @endcode
6685 *
6686 * A10
6687 *
6688 * @code
6689 *   M21(i, j) +=
6690 *   (-0.5 * fe_faces1.shape_grad(i, q_index) *
6691 *   normals[q_index] *
6692 *   fe_faces0.shape_value(j, q_index) +
6693 *   0.5 * fe_faces0.shape_grad(j, q_index) *
6694 *   normals[q_index] *
6695 *   fe_faces1.shape_value(i, q_index) -
6696 *   (penalty_constant * hf) *
6697 *   fe_faces1.shape_value(i, q_index) *
6698 *   fe_faces0.shape_value(j, q_index)) *
6699 *   fe_faces1.JxW(q_index);
6700 *  
6701 * @endcode
6702 *
6703 * A11
6704 *
6705 * @code
6706 *   M22(i, j) +=
6707 *   (0.5 * fe_faces1.shape_grad(i, q_index) *
6708 *   normals[q_index] *
6709 *   fe_faces1.shape_value(j, q_index) +
6710 *   0.5 * fe_faces1.shape_grad(j, q_index) *
6711 *   normals[q_index] *
6712 *   fe_faces1.shape_value(i, q_index) +
6713 *   (penalty_constant * hf) *
6714 *   fe_faces1.shape_value(i, q_index) *
6715 *   fe_faces1.shape_value(j, q_index)) *
6716 *   fe_faces1.JxW(q_index);
6717 *   }
6718 *   }
6719 *   }
6720 *  
6721 * @endcode
6722 *
6723 * distribute DoFs accordingly
6724 *
6725
6726 *
6727 *
6728 * @code
6729 *   neigh_cell->get_dof_indices(local_dof_indices_neighbor);
6730 *  
6731 *   constraints.distribute_local_to_global(
6732 *   M11, local_dof_indices, system_matrix);
6733 *   constraints.distribute_local_to_global(
6734 *   M12,
6735 *   local_dof_indices,
6736 *   local_dof_indices_neighbor,
6737 *   system_matrix);
6738 *   constraints.distribute_local_to_global(
6739 *   M21,
6740 *   local_dof_indices_neighbor,
6741 *   local_dof_indices,
6742 *   system_matrix);
6743 *   constraints.distribute_local_to_global(
6744 *   M22, local_dof_indices_neighbor, system_matrix);
6745 *  
6746 *   } // check idx neighbors
6747 *   } // over faces
6748 *   }
6749 *   constraints.distribute_local_to_global(cell_matrix,
6750 *   cell_rhs,
6751 *   local_dof_indices,
6752 *   system_matrix,
6753 *   system_rhs);
6754 *   }
6755 *   }
6756 *   system_matrix.compress(VectorOperation::add);
6757 *   system_rhs.compress(VectorOperation::add);
6758 *   }
6759 *  
6760 *   } // namespace ::PolyUtils
6761 *  
6762 *   #endif
6763 * @endcode
6764
6765
6766<a name="ann-source/agglomeration_handler.cc"></a>
6767<h1>Annotated version of source/agglomeration_handler.cc</h1>
6768 *
6769 *
6770 *
6771 *
6772 * @code
6773 *   /* -----------------------------------------------------------------------------
6774 *   *
6775 *   * SPDX-License-Identifier: LGPL-2.1-or-later
6776 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
6777 *   * Andrea Cangiani
6778 *   *
6779 *   * This file is part of the deal.II code gallery.
6780 *   *
6781 *   * -----------------------------------------------------------------------------
6782 *   */
6783 *  
6784 *   #include <deal.II/base/quadrature_lib.h>
6785 *   #include <deal.II/lac/sparsity_tools.h>
6786 *  
6787 *   #include <agglomeration_handler.h>
6788 *  
6789 *   template <int dim, int spacedim>
6790 *   AgglomerationHandler<dim, spacedim>::AgglomerationHandler(
6791 *   const GridTools::Cache<dim, spacedim> &cache_tria)
6792 *   : cached_tria(std::make_unique<GridTools::Cache<dim, spacedim>>(
6793 *   cache_tria.get_triangulation(),
6794 *   cache_tria.get_mapping()))
6795 *   , communicator(cache_tria.get_triangulation().get_mpi_communicator())
6796 *   {
6797 *   Assert(dim == spacedim, ExcNotImplemented("Not available with codim > 0"));
6798 *   Assert(dim == 2 || dim == 3, ExcImpossibleInDim(1));
6799 *   Assert((dynamic_cast<const parallel::shared::Triangulation<dim, spacedim> *>(
6800 *   &cached_tria->get_triangulation()) == nullptr),
6801 *   ExcNotImplemented());
6802 *   Assert(cached_tria->get_triangulation().n_active_cells() > 0,
6803 *   ExcMessage(
6804 *   "The triangulation must not be empty upon calling this function."));
6805 *  
6806 *   n_agglomerations = 0;
6807 *   hybrid_mesh = false;
6808 *   initialize_agglomeration_data(cached_tria);
6809 *   }
6810 *  
6811 *  
6812 *  
6813 *   template <int dim, int spacedim>
6814 *   typename AgglomerationHandler<dim, spacedim>::agglomeration_iterator
6815 *   AgglomerationHandler<dim, spacedim>::define_agglomerate(
6816 *   const AgglomerationContainer &cells)
6817 *   {
6818 *   Assert(cells.size() > 0, ExcMessage("No cells to be agglomerated."));
6819 *  
6820 *   if (cells.size() == 1)
6821 *   hybrid_mesh = true; // mesh is made also by classical cells
6822 *  
6823 * @endcode
6824 *
6825 * First index drives the selection of the master cell. After that, store the
6826 * master cell.
6827 *
6828 * @code
6829 *   const types::global_cell_index global_master_idx =
6830 *   cells[0]->global_active_cell_index();
6831 *   const types::global_cell_index master_idx = cells[0]->active_cell_index();
6832 *   master_cells_container.push_back(cells[0]);
6833 *   master_slave_relationships[global_master_idx] = -1;
6834 *  
6835 *   const typename DoFHandler<dim>::active_cell_iterator cell_dh =
6836 *   cells[0]->as_dof_handler_iterator(agglo_dh);
6837 *   cell_dh->set_active_fe_index(CellAgglomerationType::master);
6838 *  
6839 * @endcode
6840 *
6841 * Store slave cells and save the relationship with the parent
6842 *
6843 * @code
6844 *   std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
6845 *   slaves;
6846 *   slaves.reserve(cells.size() - 1);
6847 * @endcode
6848 *
6849 * exclude first cell since it's the master cell
6850 *
6851 * @code
6852 *   for (auto it = ++cells.begin(); it != cells.end(); ++it)
6853 *   {
6854 *   slaves.push_back(*it);
6855 *   master_slave_relationships[(*it)->global_active_cell_index()] =
6856 *   global_master_idx; // mark each slave
6857 *   master_slave_relationships_iterators[(*it)->active_cell_index()] =
6858 *   cells[0];
6859 *  
6860 *   const typename DoFHandler<dim>::active_cell_iterator cell =
6861 *   (*it)->as_dof_handler_iterator(agglo_dh);
6862 *   cell->set_active_fe_index(CellAgglomerationType::slave); // slave cell
6863 *  
6864 * @endcode
6865 *
6866 * If we have a p::d::T, check that all cells are in the same subdomain.
6867 * If serial, just check that the subdomain_id is invalid.
6868 *
6869 * @code
6870 *   Assert(((*it)->subdomain_id() == tria->locally_owned_subdomain() ||
6871 *   tria->locally_owned_subdomain() == numbers::invalid_subdomain_id),
6872 *   ExcInternalError());
6873 *   }
6874 *  
6875 *   master_slave_relationships_iterators[master_idx] =
6876 *   cells[0]; // set iterator to master cell
6877 *  
6878 * @endcode
6879 *
6880 * Store the slaves of each master
6881 *
6882 * @code
6883 *   master2slaves[master_idx] = slaves;
6884 * @endcode
6885 *
6886 * Save to which polygon this agglomerate correspond
6887 *
6888 * @code
6889 *   master2polygon[master_idx] = n_agglomerations;
6890 *  
6891 *   ++n_agglomerations; // an agglomeration has been performed, record it
6892 *  
6893 *   create_bounding_box(cells); // fill the vector of bboxes
6894 *  
6895 * @endcode
6896 *
6897 * Finally, return a polygonal iterator to the polytope just constructed.
6898 *
6899 * @code
6900 *   return {cells[0], this};
6901 *   }
6902 *  
6903 *   template <int dim, int spacedim>
6904 *   typename AgglomerationHandler<dim, spacedim>::agglomeration_iterator
6905 *   AgglomerationHandler<dim, spacedim>::define_agglomerate(
6906 *   const AgglomerationContainer &cells,
6907 *   const unsigned int fecollection_size)
6908 *   {
6909 *   Assert(cells.size() > 0, ExcMessage("No cells to be agglomerated."));
6910 *  
6911 *   if (cells.size() == 1)
6912 *   hybrid_mesh = true; // mesh is made also by classical cells
6913 *  
6914 * @endcode
6915 *
6916 * First index drives the selection of the master cell. After that, store the
6917 * master cell.
6918 *
6919 * @code
6920 *   const types::global_cell_index global_master_idx =
6921 *   cells[0]->global_active_cell_index();
6922 *   const types::global_cell_index master_idx = cells[0]->active_cell_index();
6923 *   master_cells_container.push_back(cells[0]);
6924 *   master_slave_relationships[global_master_idx] = -1;
6925 *  
6926 *   const typename DoFHandler<dim>::active_cell_iterator cell_dh =
6927 *   cells[0]->as_dof_handler_iterator(agglo_dh);
6928 *   cell_dh->set_active_fe_index(CellAgglomerationType::master);
6929 *  
6930 * @endcode
6931 *
6932 * Store slave cells and save the relationship with the parent
6933 *
6934 * @code
6935 *   std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>
6936 *   slaves;
6937 *   slaves.reserve(cells.size() - 1);
6938 * @endcode
6939 *
6940 * exclude first cell since it's the master cell
6941 *
6942 * @code
6943 *   for (auto it = ++cells.begin(); it != cells.end(); ++it)
6944 *   {
6945 *   slaves.push_back(*it);
6946 *   master_slave_relationships[(*it)->global_active_cell_index()] =
6947 *   global_master_idx; // mark each slave
6948 *   master_slave_relationships_iterators[(*it)->active_cell_index()] =
6949 *   cells[0];
6950 *  
6951 *   const typename DoFHandler<dim>::active_cell_iterator cell =
6952 *   (*it)->as_dof_handler_iterator(agglo_dh);
6953 *   cell->set_active_fe_index(
6954 *   fecollection_size); // slave cell (the last index)
6955 *  
6956 * @endcode
6957 *
6958 * If we have a p::d::T, check that all cells are in the same subdomain.
6959 * If serial, just check that the subdomain_id is invalid.
6960 *
6961 * @code
6962 *   Assert(((*it)->subdomain_id() == tria->locally_owned_subdomain() ||
6963 *   tria->locally_owned_subdomain() == numbers::invalid_subdomain_id),
6964 *   ExcInternalError());
6965 *   }
6966 *  
6967 *   master_slave_relationships_iterators[master_idx] =
6968 *   cells[0]; // set iterator to master cell
6969 *  
6970 * @endcode
6971 *
6972 * Store the slaves of each master
6973 *
6974 * @code
6975 *   master2slaves[master_idx] = slaves;
6976 * @endcode
6977 *
6978 * Save to which polygon this agglomerate correspond
6979 *
6980 * @code
6981 *   master2polygon[master_idx] = n_agglomerations;
6982 *  
6983 *   ++n_agglomerations; // an agglomeration has been performed, record it
6984 *  
6985 *   create_bounding_box(cells); // fill the vector of bboxes
6986 *  
6987 * @endcode
6988 *
6989 * Finally, return a polygonal iterator to the polytope just constructed.
6990 *
6991 * @code
6992 *   return {cells[0], this};
6993 *   }
6994 *  
6995 *  
6996 *   template <int dim, int spacedim>
6997 *   void
6998 *   AgglomerationHandler<dim, spacedim>::initialize_fe_values(
6999 *   const Quadrature<dim> &cell_quadrature,
7000 *   const UpdateFlags &flags,
7001 *   const Quadrature<dim - 1> &face_quadrature,
7002 *   const UpdateFlags &face_flags)
7003 *   {
7004 *   agglomeration_quad = cell_quadrature;
7005 *   agglomeration_flags = flags;
7006 *   agglomeration_face_quad = face_quadrature;
7007 *   agglomeration_face_flags = face_flags | internal_agglomeration_face_flags;
7008 *  
7009 *  
7010 *   no_values =
7011 *   std::make_unique<FEValues<dim>>(*mapping,
7012 *   dummy_fe,
7013 *   agglomeration_quad,
7014 *   update_quadrature_points |
7015 *   update_JxW_values); // only for quadrature
7016 *   no_face_values = std::make_unique<FEFaceValues<dim>>(
7017 *   *mapping,
7018 *   dummy_fe,
7019 *   agglomeration_face_quad,
7020 *   update_quadrature_points | update_JxW_values |
7021 *   update_normal_vectors); // only for quadrature
7022 *   }
7023 *  
7024 *   template <int dim, int spacedim>
7025 *   void
7026 *   AgglomerationHandler<dim, spacedim>::initialize_fe_values(
7027 *   const hp::QCollection<dim> &cell_qcollection,
7028 *   const UpdateFlags &flags,
7029 *   const hp::QCollection<dim - 1> &face_qcollection,
7030 *   const UpdateFlags &face_flags)
7031 *   {
7032 *   agglomeration_quad_collection = cell_qcollection;
7033 *   agglomeration_flags = flags;
7034 *   agglomeration_face_quad_collection = face_qcollection;
7035 *   agglomeration_face_flags = face_flags | internal_agglomeration_face_flags;
7036 *  
7037 *   mapping_collection = hp::MappingCollection<dim>(*mapping);
7038 *   dummy_fe_collection = hp::FECollection<dim, spacedim>(dummy_fe);
7039 *   hp_no_values = std::make_unique<hp::FEValues<dim>>(
7040 *   mapping_collection,
7041 *   dummy_fe_collection,
7042 *   agglomeration_quad_collection,
7043 *   update_quadrature_points | update_JxW_values); // only for quadrature
7044 *  
7045 *   hp_no_face_values = std::make_unique<hp::FEFaceValues<dim>>(
7046 *   mapping_collection,
7047 *   dummy_fe_collection,
7048 *   agglomeration_face_quad_collection,
7049 *   update_quadrature_points | update_JxW_values |
7050 *   update_normal_vectors); // only for quadrature
7051 *   }
7052 *  
7053 *  
7054 *  
7055 *   template <int dim, int spacedim>
7056 *   unsigned int
7057 *   AgglomerationHandler<dim, spacedim>::n_agglomerated_faces_per_cell(
7058 *   const typename Triangulation<dim, spacedim>::active_cell_iterator &cell) const
7059 *   {
7060 *   unsigned int n_neighbors = 0;
7061 *   for (const auto &f : cell->face_indices())
7062 *   {
7063 *   const auto &neighboring_cell = cell->neighbor(f);
7064 *   if ((cell->face(f)->at_boundary()) ||
7065 *   (neighboring_cell->is_active() &&
7066 *   !are_cells_agglomerated(cell, neighboring_cell)))
7067 *   {
7068 *   ++n_neighbors;
7069 *   }
7070 *   }
7071 *   return n_neighbors;
7072 *   }
7073 *  
7074 *  
7075 *  
7076 *   template <int dim, int spacedim>
7077 *   void
7078 *   AgglomerationHandler<dim, spacedim>::initialize_agglomeration_data(
7079 *   const std::unique_ptr<GridTools::Cache<dim, spacedim>> &cache_tria)
7080 *   {
7081 *   tria = &(cache_tria->get_triangulation());
7082 *   mapping = &(cache_tria->get_mapping());
7083 *  
7084 *   agglo_dh.reinit(*tria);
7085 *  
7086 *   if (const auto parallel_tria = dynamic_cast<
7087 *   const ::parallel::TriangulationBase<dim, spacedim> *>(&*tria))
7088 *   {
7089 *   const std::weak_ptr<const Utilities::MPI::Partitioner> cells_partitioner =
7090 *   parallel_tria->global_active_cell_index_partitioner();
7091 *   master_slave_relationships.reinit(
7092 *   cells_partitioner.lock()->locally_owned_range(), communicator);
7093 *   }
7094 *   else
7095 *   {
7096 *   master_slave_relationships.reinit(tria->n_active_cells(), MPI_COMM_SELF);
7097 *   }
7098 *  
7099 *   polytope_cache.clear();
7100 *   bboxes.clear();
7101 *  
7102 * @endcode
7103 *
7104 * First, update the pointer
7105 *
7106 * @code
7107 *   cached_tria = std::make_unique<GridTools::Cache<dim, spacedim>>(
7108 *   cache_tria->get_triangulation(), cache_tria->get_mapping());
7109 *  
7110 *   connect_to_tria_signals();
7111 *   n_agglomerations = 0;
7112 *   }
7113 *  
7114 *  
7115 *  
7116 *   template <int dim, int spacedim>
7117 *   void
7118 *   AgglomerationHandler<dim, spacedim>::distribute_agglomerated_dofs(
7119 *   const FiniteElement<dim> &fe_space)
7120 *   {
7121 *   if (dynamic_cast<const FE_DGQ<dim> *>(&fe_space))
7122 *   fe = std::make_unique<FE_DGQ<dim>>(fe_space.degree);
7123 *   else if (dynamic_cast<const FE_SimplexDGP<dim> *>(&fe_space))
7124 *   fe = std::make_unique<FE_SimplexDGP<dim>>(fe_space.degree);
7125 *   else
7126 *   AssertThrow(
7127 *   false,
7128 *   ExcNotImplemented(
7129 *   "Currently, this interface supports only DGQ and DGP bases."));
7130 *  
7131 *   box_mapping = std::make_unique<MappingBox<dim>>(
7132 *   bboxes,
7133 *   master2polygon); // construct bounding box mapping
7134 *  
7135 *   if (hybrid_mesh)
7136 *   {
7137 * @endcode
7138 *
7139 * the mesh is composed by standard and agglomerate cells. initialize
7140 * classes needed for standard cells in order to treat that finite
7141 * element space as defined on a standard shape and not on the
7142 * BoundingBox.
7143 *
7144 * @code
7145 *   standard_scratch =
7146 *   std::make_unique<ScratchData>(*mapping,
7147 *   *fe,
7148 *   QGauss<dim>(2 * fe_space.degree + 2),
7149 *   internal_agglomeration_flags);
7150 *   }
7151 *  
7152 *  
7153 *   fe_collection.push_back(*fe); // master
7154 *   fe_collection.push_back(
7155 *   FE_Nothing<dim, spacedim>(fe->reference_cell())); // slave
7156 *  
7157 *   initialize_hp_structure();
7158 *  
7159 * @endcode
7160 *
7161 * in case the tria is distributed, communicate ghost information with
7162 * neighboring ranks
7163 *
7164 * @code
7165 *   const bool needs_ghost_info =
7166 *   dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(&*tria) !=
7167 *   nullptr;
7168 *   if (needs_ghost_info)
7169 *   setup_ghost_polytopes();
7170 *  
7171 *   setup_connectivity_of_agglomeration();
7172 *  
7173 *   if (needs_ghost_info)
7174 *   exchange_interface_values();
7175 *   }
7176 *  
7177 *   template <int dim, int spacedim>
7178 *   void
7179 *   AgglomerationHandler<dim, spacedim>::distribute_agglomerated_dofs(
7180 *   const hp::FECollection<dim, spacedim> &fe_collection_in)
7181 *   {
7182 *   is_hp_collection = true;
7183 *  
7184 *   hp_fe_collection = std::make_unique<hp::FECollection<dim, spacedim>>(
7185 *   fe_collection_in); // copy the input collection
7186 *  
7187 *   box_mapping = std::make_unique<MappingBox<dim>>(
7188 *   bboxes,
7189 *   master2polygon); // construct bounding box mapping
7190 *  
7191 *  
7192 *   if (hybrid_mesh)
7193 *   {
7194 *   AssertThrow(false,
7195 *   ExcNotImplemented(
7196 *   "Hybrid mesh is not implemented for hp::FECollection."));
7197 *   }
7198 *  
7199 *   for (unsigned int i = 0; i < fe_collection_in.size(); ++i)
7200 *   {
7201 *   if (dynamic_cast<const FESystem<dim> *>(&fe_collection_in[i]))
7202 *   {
7203 * @endcode
7204 *
7205 * System case
7206 *
7207 * @code
7208 *   for (unsigned int b = 0; b < fe_collection_in[i].n_base_elements();
7209 *   ++b)
7210 *   {
7211 *   if (!(dynamic_cast<const FE_DGQ<dim> *>(
7212 *   &fe_collection_in[i].base_element(b)) ||
7213 *   dynamic_cast<const FE_SimplexDGP<dim> *>(
7214 *   &fe_collection_in[i].base_element(b)) ||
7215 *   dynamic_cast<const FE_Nothing<dim> *>(
7216 *   &fe_collection_in[i].base_element(b))))
7217 *   AssertThrow(
7218 *   false,
7219 *   ExcNotImplemented(
7220 *   "Currently, this interface supports only DGQ and DGP bases."));
7221 *   }
7222 *   }
7223 *   else
7224 *   {
7225 * @endcode
7226 *
7227 * Scalar case
7228 *
7229 * @code
7230 *   if (!(dynamic_cast<const FE_DGQ<dim> *>(&fe_collection_in[i]) ||
7231 *   dynamic_cast<const FE_SimplexDGP<dim> *>(&fe_collection_in[i])))
7232 *   AssertThrow(
7233 *   false,
7234 *   ExcNotImplemented(
7235 *   "Currently, this interface supports only DGQ and DGP bases."));
7236 *   }
7237 *   fe_collection.push_back(fe_collection_in[i]);
7238 *   }
7239 *  
7240 *   Assert(fe_collection[0].n_components() >= 1,
7241 *   ExcMessage("Invalid FE: must have at least one component."));
7242 *   if (fe_collection[0].n_components() == 1)
7243 *   {
7244 *   fe_collection.push_back(FE_Nothing<dim, spacedim>());
7245 *   }
7246 *   else if (fe_collection[0].n_components() > 1)
7247 *   {
7248 *   std::vector<const FiniteElement<dim, spacedim> *> base_elements;
7249 *   std::vector<unsigned int> multiplicities;
7250 *   for (unsigned int b = 0; b < fe_collection[0].n_base_elements(); ++b)
7251 *   {
7252 *   base_elements.push_back(new FE_Nothing<dim, spacedim>());
7253 *   multiplicities.push_back(fe_collection[0].element_multiplicity(b));
7254 *   }
7255 *   FESystem<dim, spacedim> fe_system_nothing(base_elements, multiplicities);
7256 *   for (const auto *ptr : base_elements)
7257 *   delete ptr;
7258 *   fe_collection.push_back(fe_system_nothing);
7259 *   }
7260 *  
7261 *   initialize_hp_structure();
7262 *  
7263 * @endcode
7264 *
7265 * in case the tria is distributed, communicate ghost information with
7266 * neighboring ranks
7267 *
7268 * @code
7269 *   const bool needs_ghost_info =
7270 *   dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(&*tria) !=
7271 *   nullptr;
7272 *   if (needs_ghost_info)
7273 *   setup_ghost_polytopes();
7274 *  
7275 *   setup_connectivity_of_agglomeration();
7276 *  
7277 *   if (needs_ghost_info)
7278 *   exchange_interface_values();
7279 *   }
7280 *  
7281 *   template <int dim, int spacedim>
7282 *   void
7283 *   AgglomerationHandler<dim, spacedim>::create_bounding_box(
7284 *   const AgglomerationContainer &polytope)
7285 *   {
7286 *   Assert(n_agglomerations > 0,
7287 *   ExcMessage("No agglomeration has been performed."));
7288 *   Assert(dim > 1, ExcNotImplemented());
7289 *  
7290 *   std::vector<Point<spacedim>> pts; // store all the vertices
7291 *   for (const auto &cell : polytope)
7292 *   for (const auto i : cell->vertex_indices())
7293 *   pts.push_back(cell->vertex(i));
7294 *  
7295 *   bboxes.emplace_back(pts);
7296 *   }
7297 *  
7298 *  
7299 *  
7300 *   template <int dim, int spacedim>
7301 *   void
7302 *   AgglomerationHandler<dim, spacedim>::setup_connectivity_of_agglomeration()
7303 *   {
7304 *   Assert(master_cells_container.size() > 0,
7305 *   ExcMessage("No agglomeration has been performed."));
7306 *   Assert(
7307 *   agglo_dh.n_dofs() > 0,
7308 *   ExcMessage(
7309 *   "The DoFHandler associated to the agglomeration has not been initialized."
7310 *   "It's likely that you forgot to distribute the DoFs. You may want"
7311 *   "to check if a call to `initialize_hp_structure()` has been done."));
7312 *  
7313 *   number_of_agglomerated_faces.resize(master2polygon.size(), 0);
7314 *   for (const auto &cell : master_cells_container)
7315 *   {
7316 *   internal::AgglomerationHandlerImplementation<dim, spacedim>::
7317 *   setup_master_neighbor_connectivity(cell, *this);
7318 *   }
7319 *  
7320 *   if (Utilities::MPI::job_supports_mpi())
7321 *   {
7322 * @endcode
7323 *
7324 * communicate the number of faces
7325 *
7326 * @code
7327 *   recv_n_faces = Utilities::MPI::some_to_some(communicator, local_n_faces);
7328 *  
7329 * @endcode
7330 *
7331 * send information about boundaries and neighboring polytopes id
7332 *
7333 * @code
7334 *   recv_bdary_info =
7335 *   Utilities::MPI::some_to_some(communicator, local_bdary_info);
7336 *  
7337 *   recv_ghosted_master_id =
7338 *   Utilities::MPI::some_to_some(communicator, local_ghosted_master_id);
7339 *   }
7340 *   }
7341 *  
7342 *  
7343 *  
7344 *   template <int dim, int spacedim>
7345 *   void
7346 *   AgglomerationHandler<dim, spacedim>::exchange_interface_values()
7347 *   {
7348 *   const unsigned int dofs_per_cell = fe->dofs_per_cell;
7349 *   for (const auto &polytope : polytope_iterators())
7350 *   {
7351 *   if (polytope->is_locally_owned())
7352 *   {
7353 *   const unsigned int n_faces = polytope->n_faces();
7354 *   for (unsigned int f = 0; f < n_faces; ++f)
7355 *   {
7356 *   if (!polytope->at_boundary(f))
7357 *   {
7358 *   const auto &neigh_polytope = polytope->neighbor(f);
7359 *   if (!neigh_polytope->is_locally_owned())
7360 *   {
7361 * @endcode
7362 *
7363 * Neighboring polytope is ghosted.
7364 *
7365
7366 *
7367 * Compute shape functions at the interface
7368 *
7369 * @code
7370 *   const auto &current_fe = reinit(polytope, f);
7371 *  
7372 *   std::vector<Point<spacedim>> qpoints_to_send =
7373 *   current_fe.get_quadrature_points();
7374 *  
7375 *   const std::vector<double> &jxws_to_send =
7376 *   current_fe.get_JxW_values();
7377 *  
7378 *   const std::vector<Tensor<1, spacedim>> &normals_to_send =
7379 *   current_fe.get_normal_vectors();
7380 *  
7381 *  
7382 *   const types::subdomain_id neigh_rank =
7383 *   neigh_polytope->subdomain_id();
7384 *  
7385 *   std::pair<CellId, unsigned int> cell_and_face{
7386 *   polytope->id(), f};
7387 * @endcode
7388 *
7389 * Prepare data to send
7390 *
7391 * @code
7392 *   local_qpoints[neigh_rank].emplace(cell_and_face,
7393 *   qpoints_to_send);
7394 *  
7395 *   local_jxws[neigh_rank].emplace(cell_and_face,
7396 *   jxws_to_send);
7397 *  
7398 *   local_normals[neigh_rank].emplace(cell_and_face,
7399 *   normals_to_send);
7400 *  
7401 *  
7402 *   const unsigned int n_qpoints = qpoints_to_send.size();
7403 *  
7404 * @endcode
7405 *
7406 * TODO: check `agglomeration_flags` before computing
7407 * values and gradients.
7408 *
7409 * @code
7410 *   std::vector<std::vector<double>> values_per_qpoints(
7411 *   dofs_per_cell);
7412 *  
7413 *   std::vector<std::vector<Tensor<1, spacedim>>>
7414 *   gradients_per_qpoints(dofs_per_cell);
7415 *  
7416 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
7417 *   {
7418 *   values_per_qpoints[i].resize(n_qpoints);
7419 *   gradients_per_qpoints[i].resize(n_qpoints);
7420 *   for (unsigned int q = 0; q < n_qpoints; ++q)
7421 *   {
7422 *   values_per_qpoints[i][q] =
7423 *   current_fe.shape_value(i, q);
7424 *   gradients_per_qpoints[i][q] =
7425 *   current_fe.shape_grad(i, q);
7426 *   }
7427 *   }
7428 *  
7429 *   local_values[neigh_rank].emplace(cell_and_face,
7430 *   values_per_qpoints);
7431 *   local_gradients[neigh_rank].emplace(
7432 *   cell_and_face, gradients_per_qpoints);
7433 *   }
7434 *   }
7435 *   }
7436 *   }
7437 *   }
7438 *  
7439 * @endcode
7440 *
7441 * Finally, exchange with neighboring ranks
7442 *
7443 * @code
7444 *   recv_qpoints = Utilities::MPI::some_to_some(communicator, local_qpoints);
7445 *   recv_jxws = Utilities::MPI::some_to_some(communicator, local_jxws);
7446 *   recv_normals = Utilities::MPI::some_to_some(communicator, local_normals);
7447 *   recv_values = Utilities::MPI::some_to_some(communicator, local_values);
7448 *   recv_gradients = Utilities::MPI::some_to_some(communicator, local_gradients);
7449 *   }
7450 *  
7451 *  
7452 *  
7453 *   template <int dim, int spacedim>
7454 *   Quadrature<dim>
7455 *   AgglomerationHandler<dim, spacedim>::agglomerated_quadrature(
7456 *   const typename AgglomerationHandler<dim, spacedim>::AgglomerationContainer
7457 *   &cells,
7458 *   const typename Triangulation<dim, spacedim>::active_cell_iterator
7459 *   &master_cell) const
7460 *   {
7461 *   Assert(is_master_cell(master_cell),
7462 *   ExcMessage("This must be a master cell."));
7463 *  
7464 *   std::vector<Point<dim>> vec_pts;
7465 *   std::vector<double> vec_JxWs;
7466 *  
7467 *   if (!is_hp_collection)
7468 *   {
7469 * @endcode
7470 *
7471 * Original version: handle case without hp::FECollection
7472 *
7473 * @code
7474 *   for (const auto &dummy_cell : cells)
7475 *   {
7476 *   no_values->reinit(dummy_cell);
7477 *   auto q_points = no_values->get_quadrature_points(); // real qpoints
7478 *   const auto &JxWs = no_values->get_JxW_values();
7479 *  
7480 *   std::transform(q_points.begin(),
7481 *   q_points.end(),
7482 *   std::back_inserter(vec_pts),
7483 *   [&](const Point<spacedim> &p) { return p; });
7484 *   std::transform(JxWs.begin(),
7485 *   JxWs.end(),
7486 *   std::back_inserter(vec_JxWs),
7487 *   [&](const double w) { return w; });
7488 *   }
7489 *   }
7490 *   else
7491 *   {
7492 * @endcode
7493 *
7494 * Handle the hp::FECollection case
7495 *
7496 * @code
7497 *   const auto &master_cell_as_dh_iterator =
7498 *   master_cell->as_dof_handler_iterator(agglo_dh);
7499 *   for (const auto &dummy_cell : cells)
7500 *   {
7501 * @endcode
7502 *
7503 * The following verbose call is necessary to handle cases where
7504 * different slave cells on different polytopes use different
7505 * quadrature rules. If the hp::QCollection contains multiple
7506 * elements, calling hp_no_values->reinit(dummy_cell) won't work
7507 * because it cannot infer the correct quadrature rule. By explicitly
7508 * passing the active FE index as q_index, and setting mapping_index
7509 * and fe_index to 0, we ensure that the dummy cell uses the same
7510 * quadrature rule as its corresponding master cell. This assumes a
7511 * one-to-one correspondence between hp::QCollection and
7512 * hp::FECollection, which is the convention in deal.II. However, this
7513 * implementation does not support cases where hp::QCollection and
7514 * hp::FECollection have different sizes.
7515 * TODO: Refactor the architecture to better handle numerical
7516 * integration for hp::QCollection.
7517 *
7518 * @code
7519 *   hp_no_values->reinit(dummy_cell,
7520 *   master_cell_as_dh_iterator->active_fe_index(),
7521 *   0,
7522 *   0);
7523 *   auto q_points = hp_no_values->get_present_fe_values()
7524 *   .get_quadrature_points(); // real qpoints
7525 *   const auto &JxWs =
7526 *   hp_no_values->get_present_fe_values().get_JxW_values();
7527 *  
7528 *   std::transform(q_points.begin(),
7529 *   q_points.end(),
7530 *   std::back_inserter(vec_pts),
7531 *   [&](const Point<spacedim> &p) { return p; });
7532 *   std::transform(JxWs.begin(),
7533 *   JxWs.end(),
7534 *   std::back_inserter(vec_JxWs),
7535 *   [&](const double w) { return w; });
7536 *   }
7537 *   }
7538 *  
7539 * @endcode
7540 *
7541 * Map back each point in real space by using the map associated to the
7542 * bounding box.
7543 *
7544 * @code
7545 *   std::vector<Point<dim>> unit_points(vec_pts.size());
7546 *   const auto &bbox =
7547 *   bboxes[master2polygon.at(master_cell->active_cell_index())];
7548 *   unit_points.reserve(vec_pts.size());
7549 *  
7550 *   for (unsigned int i = 0; i < vec_pts.size(); i++)
7551 *   unit_points[i] = bbox.real_to_unit(vec_pts[i]);
7552 *  
7553 *   return Quadrature<dim>(unit_points, vec_JxWs);
7554 *   }
7555 *  
7556 *  
7557 *  
7558 *   template <int dim, int spacedim>
7559 *   void
7560 *   AgglomerationHandler<dim, spacedim>::initialize_hp_structure()
7561 *   {
7562 *   Assert(agglo_dh.get_triangulation().n_cells() > 0,
7563 *   ExcMessage(
7564 *   "Triangulation must not be empty upon calling this function."));
7565 *   Assert(n_agglomerations > 0,
7566 *   ExcMessage("No agglomeration has been performed."));
7567 *  
7568 *   agglo_dh.distribute_dofs(fe_collection);
7569 * @endcode
7570 *
7571 * euler_mapping = std::make_unique<
7572 * MappingFEField<dim, spacedim,
7573 * LinearAlgebra::distributed::Vector<double>>>( euler_dh, euler_vector);
7574 *
7575 * @code
7576 *   }
7577 *  
7578 *  
7579 *  
7580 *   template <int dim, int spacedim>
7581 *   const FEValues<dim, spacedim> &
7582 *   AgglomerationHandler<dim, spacedim>::reinit(
7583 *   const AgglomerationIterator<dim, spacedim> &polytope) const
7584 *   {
7585 * @endcode
7586 *
7587 * Assert(euler_mapping,
7588 * ExcMessage("The mapping describing the physical element stemming
7589 * from "
7590 * "agglomeration has not been set up."));
7591 *
7592
7593 *
7594 *
7595 * @code
7596 *   const auto &deal_cell = polytope->as_dof_handler_iterator(agglo_dh);
7597 *  
7598 * @endcode
7599 *
7600 * First check if the polytope is made just by a single cell. If so, use
7601 * classical FEValues
7602 * if (polytope->n_background_cells() == 1)
7603 * return standard_scratch->reinit(deal_cell);
7604 *
7605
7606 *
7607 *
7608 * @code
7609 *   const auto &agglo_cells = polytope->get_agglomerate();
7610 *  
7611 *   Quadrature<dim> agglo_quad = agglomerated_quadrature(agglo_cells, deal_cell);
7612 *  
7613 *   if (!is_hp_collection)
7614 *   {
7615 * @endcode
7616 *
7617 * Original version: handle case without hp::FECollection
7618 *
7619 * @code
7620 *   agglomerated_scratch = std::make_unique<ScratchData>(*box_mapping,
7621 *   fe_collection[0],
7622 *   agglo_quad,
7623 *   agglomeration_flags);
7624 *   }
7625 *   else
7626 *   {
7627 * @endcode
7628 *
7629 * Handle the hp::FECollection case
7630 *
7631 * @code
7632 *   agglomerated_scratch = std::make_unique<ScratchData>(*box_mapping,
7633 *   polytope->get_fe(),
7634 *   agglo_quad,
7635 *   agglomeration_flags);
7636 *   }
7637 *   return agglomerated_scratch->reinit(deal_cell);
7638 *   }
7639 *  
7640 *  
7641 *  
7642 *   template <int dim, int spacedim>
7644 *   AgglomerationHandler<dim, spacedim>::reinit_master(
7646 *   const unsigned int face_index,
7648 *   &agglo_isv_ptr) const
7649 *   {
7650 *   return internal::AgglomerationHandlerImplementation<dim, spacedim>::
7651 *   reinit_master(cell, face_index, agglo_isv_ptr, *this);
7652 *   }
7653 *  
7654 *  
7655 *  
7656 *   template <int dim, int spacedim>
7658 *   AgglomerationHandler<dim, spacedim>::reinit(
7659 *   const AgglomerationIterator<dim, spacedim> &polytope,
7660 *   const unsigned int face_index) const
7661 *   {
7662 * @endcode
7663 *
7664 * Assert(euler_mapping,
7665 * ExcMessage("The mapping describing the physical element stemming
7666 * from "
7667 * "agglomeration has not been set up."));
7668 *
7669
7670 *
7671 *
7672 * @code
7673 *   const auto &deal_cell = polytope->as_dof_handler_iterator(agglo_dh);
7674 *   Assert(is_master_cell(deal_cell), ExcMessage("This should be true."));
7675 *  
7676 *   return internal::AgglomerationHandlerImplementation<dim, spacedim>::
7677 *   reinit_master(deal_cell, face_index, agglomerated_isv_bdary, *this);
7678 *   }
7679 *  
7680 *  
7681 *  
7682 *   template <int dim, int spacedim>
7683 *   std::pair<const FEValuesBase<dim, spacedim> &,
7685 *   AgglomerationHandler<dim, spacedim>::reinit_interface(
7686 *   const AgglomerationIterator<dim, spacedim> &polytope_in,
7687 *   const AgglomerationIterator<dim, spacedim> &neigh_polytope,
7688 *   const unsigned int local_in,
7689 *   const unsigned int local_neigh) const
7690 *   {
7691 * @endcode
7692 *
7693 * If current and neighboring polytopes are both locally owned, then compute
7694 * the jump in the classical way without needing information about ghosted
7695 * entities.
7696 *
7697 * @code
7698 *   if (polytope_in->is_locally_owned() && neigh_polytope->is_locally_owned())
7699 *   {
7700 *   const auto &cell_in = polytope_in->as_dof_handler_iterator(agglo_dh);
7701 *   const auto &neigh_cell =
7702 *   neigh_polytope->as_dof_handler_iterator(agglo_dh);
7703 *  
7704 *   const auto &fe_in =
7705 *   internal::AgglomerationHandlerImplementation<dim, spacedim>::
7706 *   reinit_master(cell_in, local_in, agglomerated_isv, *this);
7707 *   const auto &fe_out =
7708 *   internal::AgglomerationHandlerImplementation<dim, spacedim>::
7709 *   reinit_master(neigh_cell, local_neigh, agglomerated_isv_neigh, *this);
7710 *   std::pair<const FEValuesBase<dim, spacedim> &,
7712 *   my_p(fe_in, fe_out);
7713 *  
7714 *   return my_p;
7715 *   }
7716 *   else
7717 *   {
7718 *   Assert((polytope_in->is_locally_owned() &&
7719 *   !neigh_polytope->is_locally_owned()),
7720 *   ExcInternalError());
7721 *  
7722 *   const auto &cell = polytope_in->as_dof_handler_iterator(agglo_dh);
7723 *   const auto &bbox = bboxes[master2polygon.at(cell->active_cell_index())];
7724 * @endcode
7725 *
7726 * const double bbox_measure = bbox.volume();
7727 *
7728
7729 *
7730 *
7731 * @code
7732 *   const unsigned int neigh_rank = neigh_polytope->subdomain_id();
7733 *   const CellId &neigh_id = neigh_polytope->id();
7734 *  
7735 * @endcode
7736 *
7737 * Retrieve qpoints,JxWs, normals sent previously from the neighboring
7738 * rank.
7739 *
7740 * @code
7741 *   std::vector<Point<spacedim>> &real_qpoints =
7742 *   recv_qpoints.at(neigh_rank).at({neigh_id, local_neigh});
7743 *  
7744 *   const auto &JxWs = recv_jxws.at(neigh_rank).at({neigh_id, local_neigh});
7745 *  
7746 *   std::vector<Tensor<1, spacedim>> &normals =
7747 *   recv_normals.at(neigh_rank).at({neigh_id, local_neigh});
7748 *  
7749 * @endcode
7750 *
7751 * Apply the necessary scalings due to the bbox.
7752 *
7753 * @code
7754 *   std::vector<Point<spacedim>> final_unit_q_points;
7755 *   std::transform(real_qpoints.begin(),
7756 *   real_qpoints.end(),
7757 *   std::back_inserter(final_unit_q_points),
7758 *   [&](const Point<spacedim> &p) {
7759 *   return bbox.real_to_unit(p);
7760 *   });
7761 *  
7762 * @endcode
7763 *
7764 * std::vector<double> scale_factors(final_unit_q_points.size());
7765 * std::vector<double> scaled_weights(final_unit_q_points.size());
7766 * std::vector<Tensor<1, dim>> scaled_normals(final_unit_q_points.size());
7767 *
7768
7769 *
7770 * Since we received normal vectors from a neighbor, we have to swap
7771 * the
7772 * // sign of the vector in order to have outward normals.
7773 * for (unsigned int q = 0; q < final_unit_q_points.size(); ++q)
7774 * {
7775 * for (unsigned int direction = 0; direction < spacedim; ++direction)
7776 * scaled_normals[q][direction] =
7777 * normals[q][direction] * (bbox.side_length(direction));
7778 *
7779
7780 *
7781 * scaled_normals[q] *= -1;
7782 *
7783
7784 *
7785 * scaled_weights[q] =
7786 * (JxWs[q] * scaled_normals[q].norm()) / bbox_measure;
7787 * scaled_normals[q] /= scaled_normals[q].norm();
7788 * }
7789 *
7790 * @code
7791 *   for (unsigned int q = 0; q < final_unit_q_points.size(); ++q)
7792 *   normals[q] *= -1;
7793 *  
7794 *  
7796 *   final_unit_q_points, JxWs, normals);
7797 *  
7798 *   agglomerated_isv =
7799 *   std::make_unique<NonMatching::FEImmersedSurfaceValues<spacedim>>(
7800 *   *box_mapping, *fe, surface_quad, agglomeration_face_flags);
7801 *  
7802 *  
7803 *   agglomerated_isv->reinit(cell);
7804 *  
7805 *   std::pair<const FEValuesBase<dim, spacedim> &,
7807 *   my_p(*agglomerated_isv, *agglomerated_isv);
7808 *  
7809 *   return my_p;
7810 *   }
7811 *   }
7812 *  
7813 *  
7814 *  
7815 *   template <int dim, int spacedim>
7816 *   template <typename SparsityPatternType, typename Number>
7817 *   void
7818 *   AgglomerationHandler<dim, spacedim>::create_agglomeration_sparsity_pattern(
7819 *   SparsityPatternType &dsp,
7820 *   const AffineConstraints<Number> &constraints,
7821 *   const bool keep_constrained_dofs,
7822 *   const types::subdomain_id subdomain_id)
7823 *   {
7824 *   Assert(n_agglomerations > 0,
7825 *   ExcMessage("The agglomeration has not been set up correctly."));
7826 *   Assert(dsp.empty(),
7827 *   ExcMessage(
7828 *   "The Sparsity pattern must be empty upon calling this function."));
7829 *  
7830 *   const IndexSet &locally_owned_dofs = agglo_dh.locally_owned_dofs();
7831 *   const IndexSet locally_relevant_dofs =
7833 *  
7834 *   if constexpr (std::is_same_v<SparsityPatternType, DynamicSparsityPattern>)
7835 *   dsp.reinit(locally_owned_dofs.size(),
7836 *   locally_owned_dofs.size(),
7837 *   locally_relevant_dofs);
7838 *   else if constexpr (std::is_same_v<SparsityPatternType,
7840 *   dsp.reinit(locally_owned_dofs, communicator);
7841 *   else
7842 *   AssertThrow(false, ExcNotImplemented());
7843 *  
7844 * @endcode
7845 *
7846 * Create the sparsity pattern corresponding only to volumetric terms. The
7847 * fluxes needed by DG methods will be filled later.
7848 *
7849 * @code
7851 *   agglo_dh, dsp, constraints, keep_constrained_dofs, subdomain_id);
7852 *  
7853 *  
7854 *   if (!is_hp_collection)
7855 *   {
7856 * @endcode
7857 *
7858 * Original version: handle case without hp::FECollection
7859 *
7860 * @code
7861 *   const unsigned int dofs_per_cell = agglo_dh.get_fe(0).n_dofs_per_cell();
7862 *   std::vector<types::global_dof_index> current_dof_indices(dofs_per_cell);
7863 *   std::vector<types::global_dof_index> neighbor_dof_indices(dofs_per_cell);
7864 *  
7865 * @endcode
7866 *
7867 * Loop over all locally owned polytopes, find the neighbor (also ghosted)
7868 * and add fluxes to the sparsity pattern.
7869 *
7870 * @code
7871 *   for (const auto &polytope : polytope_iterators())
7872 *   {
7873 *   if (polytope->is_locally_owned())
7874 *   {
7875 *   const unsigned int n_current_faces = polytope->n_faces();
7876 *   polytope->get_dof_indices(current_dof_indices);
7877 *   for (unsigned int f = 0; f < n_current_faces; ++f)
7878 *   {
7879 *   const auto &neigh_polytope = polytope->neighbor(f);
7880 *   if (neigh_polytope.state() == IteratorState::valid)
7881 *   {
7882 *   neigh_polytope->get_dof_indices(neighbor_dof_indices);
7883 *   constraints.add_entries_local_to_global(
7884 *   current_dof_indices,
7885 *   neighbor_dof_indices,
7886 *   dsp,
7887 *   keep_constrained_dofs,
7888 *   {});
7889 *   }
7890 *   }
7891 *   }
7892 *   }
7893 *   }
7894 *   else
7895 *   {
7896 * @endcode
7897 *
7898 * Handle the hp::FECollection case
7899 *
7900
7901 *
7902 * Loop over all locally owned polytopes, find the neighbor (also ghosted)
7903 * and add fluxes to the sparsity pattern.
7904 *
7905 * @code
7906 *   for (const auto &polytope : polytope_iterators())
7907 *   {
7908 *   if (polytope->is_locally_owned())
7909 *   {
7910 *   const unsigned int current_dofs_per_cell =
7911 *   polytope->get_fe().dofs_per_cell;
7912 *   std::vector<types::global_dof_index> current_dof_indices(
7913 *   current_dofs_per_cell);
7914 *  
7915 *   const unsigned int n_current_faces = polytope->n_faces();
7916 *   polytope->get_dof_indices(current_dof_indices);
7917 *   for (unsigned int f = 0; f < n_current_faces; ++f)
7918 *   {
7919 *   const auto &neigh_polytope = polytope->neighbor(f);
7920 *   if (neigh_polytope.state() == IteratorState::valid)
7921 *   {
7922 *   const unsigned int neighbor_dofs_per_cell =
7923 *   neigh_polytope->get_fe().dofs_per_cell;
7924 *   std::vector<types::global_dof_index> neighbor_dof_indices(
7925 *   neighbor_dofs_per_cell);
7926 *  
7927 *   neigh_polytope->get_dof_indices(neighbor_dof_indices);
7928 *   constraints.add_entries_local_to_global(
7929 *   current_dof_indices,
7930 *   neighbor_dof_indices,
7931 *   dsp,
7932 *   keep_constrained_dofs,
7933 *   {});
7934 *   }
7935 *   }
7936 *   }
7937 *   }
7938 *   }
7939 *  
7940 *  
7941 *  
7942 *   if constexpr (std::is_same_v<SparsityPatternType,
7944 *   dsp.compress();
7945 *   }
7946 *  
7947 *  
7948 *  
7949 *   template <int dim, int spacedim>
7950 *   void
7951 *   AgglomerationHandler<dim, spacedim>::setup_ghost_polytopes()
7952 *   {
7953 *   [[maybe_unused]] const auto parallel_triangulation =
7954 *   dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(&*tria);
7955 *   Assert(parallel_triangulation != nullptr, ExcInternalError());
7956 *  
7957 *   const unsigned int n_dofs_per_cell = fe->dofs_per_cell;
7958 *   std::vector<types::global_dof_index> global_dof_indices(n_dofs_per_cell);
7959 *   for (const auto &polytope : polytope_iterators())
7960 *   if (polytope->is_locally_owned())
7961 *   {
7962 *   const CellId &master_cell_id = polytope->id();
7963 *  
7964 *   const auto polytope_dh = polytope->as_dof_handler_iterator(agglo_dh);
7965 *   polytope_dh->get_dof_indices(global_dof_indices);
7966 *  
7967 *  
7968 *   const auto &agglomerate = polytope->get_agglomerate();
7969 *  
7970 *   for (const auto &cell : agglomerate)
7971 *   {
7972 * @endcode
7973 *
7974 * interior, locally owned, cell
7975 *
7976 * @code
7977 *   for (const auto &f : cell->face_indices())
7978 *   {
7979 *   if (!cell->at_boundary(f))
7980 *   {
7981 *   const auto &neighbor = cell->neighbor(f);
7982 *   if (neighbor->is_ghost())
7983 *   {
7984 * @endcode
7985 *
7986 * key of the map: the rank to which send the data
7987 *
7988 * @code
7989 *   const types::subdomain_id neigh_rank =
7990 *   neighbor->subdomain_id();
7991 *  
7992 * @endcode
7993 *
7994 * inform the "standard" neighbor about the neighboring
7995 * id and its master cell
7996 *
7997 * @code
7998 *   local_cell_ids_neigh_cell[neigh_rank].emplace(
7999 *   cell->id(), master_cell_id);
8000 *  
8001 * @endcode
8002 *
8003 * inform the neighboring rank that this master cell
8004 * (hence polytope) has the following DoF indices
8005 *
8006 * @code
8007 *   local_ghost_dofs[neigh_rank].emplace(
8008 *   master_cell_id, global_dof_indices);
8009 *  
8010 * @endcode
8011 *
8012 * ...same for bounding boxes
8013 *
8014 * @code
8015 *   const auto &bbox = bboxes[polytope->index()];
8016 *   local_ghosted_bbox[neigh_rank].emplace(master_cell_id,
8017 *   bbox);
8018 *   }
8019 *   }
8020 *   }
8021 *   }
8022 *   }
8023 *  
8024 *   recv_cell_ids_neigh_cell =
8025 *   Utilities::MPI::some_to_some(communicator, local_cell_ids_neigh_cell);
8026 *  
8027 * @endcode
8028 *
8029 * Exchange with neighboring ranks the neighboring bounding boxes
8030 *
8031 * @code
8032 *   recv_ghosted_bbox =
8033 *   Utilities::MPI::some_to_some(communicator, local_ghosted_bbox);
8034 *  
8035 * @endcode
8036 *
8037 * Exchange with neighboring ranks the neighboring ghosted DoFs
8038 *
8039 * @code
8040 *   recv_ghost_dofs =
8041 *   Utilities::MPI::some_to_some(communicator, local_ghost_dofs);
8042 *   }
8043 *  
8044 *  
8045 *  
8046 *   namespace dealii
8047 *   {
8048 *   namespace internal
8049 *   {
8050 *   template <int dim, int spacedim>
8051 *   class AgglomerationHandlerImplementation
8052 *   {
8053 *   public:
8054 *   static const FEValuesBase<dim, spacedim> &
8055 *   reinit_master(
8057 *   const unsigned int face_index,
8059 *   &agglo_isv_ptr,
8060 *   const AgglomerationHandler<dim, spacedim> &handler)
8061 *   {
8062 *   Assert(handler.is_master_cell(cell),
8063 *   ExcMessage("This cell must be a master one."));
8064 *  
8065 *   AgglomerationIterator<dim, spacedim> it{cell, &handler};
8066 *   const auto &neigh_polytope = it->neighbor(face_index);
8067 *  
8068 *   const CellId polytope_in_id = cell->id();
8069 *  
8070 * @endcode
8071 *
8072 * Retrieve the bounding box of the agglomeration
8073 *
8074 * @code
8075 *   const auto &bbox =
8076 *   handler.bboxes[handler.master2polygon.at(cell->active_cell_index())];
8077 *  
8078 *   CellId polytope_out_id;
8079 *   if (neigh_polytope.state() == IteratorState::valid)
8080 *   polytope_out_id = neigh_polytope->id();
8081 *   else
8082 *   polytope_out_id = polytope_in_id; // on the boundary. Same id
8083 *  
8084 *   const auto &common_face = handler.polytope_cache.interface.at(
8085 *   {polytope_in_id, polytope_out_id});
8086 *  
8087 *   std::vector<Point<spacedim>> final_unit_q_points;
8088 *   std::vector<double> final_weights;
8089 *   std::vector<Tensor<1, dim>> final_normals;
8090 *  
8091 *   if (!handler.is_hp_collection)
8092 *   {
8093 * @endcode
8094 *
8095 * Original version: handle case without hp::FECollection
8096 *
8097 * @code
8098 *   const unsigned int expected_qpoints =
8099 *   common_face.size() * handler.agglomeration_face_quad.size();
8100 *   final_unit_q_points.reserve(expected_qpoints);
8101 *   final_weights.reserve(expected_qpoints);
8102 *   final_normals.reserve(expected_qpoints);
8103 *  
8104 *  
8105 *   for (const auto &[deal_cell, local_face_idx] : common_face)
8106 *   {
8107 *   handler.no_face_values->reinit(deal_cell, local_face_idx);
8108 *  
8109 *   const auto &q_points =
8110 *   handler.no_face_values->get_quadrature_points();
8111 *   const auto &JxWs = handler.no_face_values->get_JxW_values();
8112 *   const auto &normals =
8113 *   handler.no_face_values->get_normal_vectors();
8114 *  
8115 *   const unsigned int n_qpoints_agglo = q_points.size();
8116 *  
8117 *   for (unsigned int q = 0; q < n_qpoints_agglo; ++q)
8118 *   {
8119 *   final_unit_q_points.push_back(
8120 *   bbox.real_to_unit(q_points[q]));
8121 *   final_weights.push_back(JxWs[q]);
8122 *   final_normals.push_back(normals[q]);
8123 *   }
8124 *   }
8125 *   }
8126 *   else
8127 *   {
8128 * @endcode
8129 *
8130 * Handle the hp::FECollection case
8131 *
8132 * @code
8133 *   unsigned int higher_order_quad_index = cell->active_fe_index();
8134 *   if (neigh_polytope.state() == IteratorState::valid)
8135 *   if (handler
8136 *   .agglomeration_face_quad_collection[cell->active_fe_index()]
8137 *   .size() <
8138 *   handler
8139 *   .agglomeration_face_quad_collection[neigh_polytope
8140 *   ->active_fe_index()]
8141 *   .size())
8142 *   higher_order_quad_index = neigh_polytope->active_fe_index();
8143 *  
8144 *   const unsigned int expected_qpoints =
8145 *   common_face.size() *
8146 *   handler
8147 *   .agglomeration_face_quad_collection[higher_order_quad_index]
8148 *   .size();
8149 *   final_unit_q_points.reserve(expected_qpoints);
8150 *   final_weights.reserve(expected_qpoints);
8151 *   final_normals.reserve(expected_qpoints);
8152 *  
8153 *   for (const auto &[deal_cell, local_face_idx] : common_face)
8154 *   {
8155 *   handler.hp_no_face_values->reinit(
8156 *   deal_cell, local_face_idx, higher_order_quad_index, 0, 0);
8157 *  
8158 *   const auto &q_points =
8159 *   handler.hp_no_face_values->get_present_fe_values()
8160 *   .get_quadrature_points();
8161 *   const auto &JxWs =
8162 *   handler.hp_no_face_values->get_present_fe_values()
8163 *   .get_JxW_values();
8164 *   const auto &normals =
8165 *   handler.hp_no_face_values->get_present_fe_values()
8166 *   .get_normal_vectors();
8167 *  
8168 *   const unsigned int n_qpoints_agglo = q_points.size();
8169 *  
8170 *   for (unsigned int q = 0; q < n_qpoints_agglo; ++q)
8171 *   {
8172 *   final_unit_q_points.push_back(
8173 *   bbox.real_to_unit(q_points[q]));
8174 *   final_weights.push_back(JxWs[q]);
8175 *   final_normals.push_back(normals[q]);
8176 *   }
8177 *   }
8178 *   }
8179 *  
8180 *  
8182 *   final_unit_q_points, final_weights, final_normals);
8183 *  
8184 *   if (!handler.is_hp_collection)
8185 *   {
8186 *   agglo_isv_ptr =
8187 *   std::make_unique<NonMatching::FEImmersedSurfaceValues<spacedim>>(
8188 *   *(handler.box_mapping),
8189 *   *(handler.fe),
8190 *   surface_quad,
8191 *   handler.agglomeration_face_flags);
8192 *   }
8193 *   else
8194 *   {
8195 *   agglo_isv_ptr =
8196 *   std::make_unique<NonMatching::FEImmersedSurfaceValues<spacedim>>(
8197 *   *(handler.box_mapping),
8198 *   cell->get_fe(),
8199 *   surface_quad,
8200 *   handler.agglomeration_face_flags);
8201 *   }
8202 *  
8203 *   agglo_isv_ptr->reinit(cell);
8204 *  
8205 *   return *agglo_isv_ptr;
8206 *   }
8207 *  
8208 *  
8209 *  
8210 *  
8216 *   static void
8217 *   setup_master_neighbor_connectivity(
8219 *   &master_cell,
8220 *   const AgglomerationHandler<dim, spacedim> &handler)
8221 *   {
8222 *   Assert(
8223 *   handler.master_slave_relationships[master_cell
8224 *   ->global_active_cell_index()] ==
8225 *   -1,
8226 *   ExcMessage("The present cell with index " +
8227 *   std::to_string(master_cell->global_active_cell_index()) +
8228 *   "is not a master one."));
8229 *  
8230 *   const auto &agglomeration = handler.get_agglomerate(master_cell);
8231 *   const types::global_cell_index current_polytope_index =
8232 *   handler.master2polygon.at(master_cell->active_cell_index());
8233 *  
8234 *   CellId current_polytope_id = master_cell->id();
8235 *  
8236 *  
8237 *   std::set<types::global_cell_index> visited_polygonal_neighbors;
8238 *  
8239 *   std::map<unsigned int, CellId> face_to_neigh_id;
8240 *  
8241 *   std::map<unsigned int, bool> is_face_at_boundary;
8242 *  
8243 * @endcode
8244 *
8245 * same as above, but with CellId
8246 *
8247 * @code
8248 *   std::set<CellId> visited_polygonal_neighbors_id;
8249 *   unsigned int ghost_counter = 0;
8250 *  
8251 *   for (const auto &cell : agglomeration)
8252 *   {
8254 *   cell->active_cell_index();
8255 *  
8256 *   const CellId cell_id = cell->id();
8257 *  
8258 *   for (const auto f : cell->face_indices())
8259 *   {
8260 *   const auto &neighboring_cell = cell->neighbor(f);
8261 *  
8262 *   const bool valid_neighbor =
8263 *   neighboring_cell.state() == IteratorState::valid;
8264 *  
8265 *   if (valid_neighbor)
8266 *   {
8267 *   if (neighboring_cell->is_locally_owned() &&
8268 *   !handler.are_cells_agglomerated(cell, neighboring_cell))
8269 *   {
8270 * @endcode
8271 *
8272 * - cell is not on the boundary,
8273 * - it's not agglomerated with the neighbor. If so,
8274 * it's a neighbor of the present agglomeration
8275 * std::cout << " (from rank) "
8277 * handler.communicator)
8278 * << std::endl;
8279 *
8280
8281 *
8282 * std::cout
8283 * << "neighbor locally owned? " << std::boolalpha
8284 * << neighboring_cell->is_locally_owned() <<
8285 * std::endl;
8286 * if (neighboring_cell->is_ghost())
8287 * handler.ghosted_indices.push_back(
8288 * neighboring_cell->active_cell_index());
8289 *
8290
8291 *
8292 * a new face of the agglomeration has been
8293 * discovered.
8294 *
8295 * @code
8296 *   handler.polygon_boundary[master_cell].push_back(
8297 *   cell->face(f));
8298 *  
8299 * @endcode
8300 *
8301 * global index of neighboring deal.II cell
8302 *
8303 * @code
8304 *   const types::global_cell_index neighboring_cell_index =
8305 *   neighboring_cell->active_cell_index();
8306 *  
8307 * @endcode
8308 *
8309 * master cell for the neighboring polytope
8310 *
8311 * @code
8312 *   const auto &master_of_neighbor =
8313 *   handler.master_slave_relationships_iterators.at(
8314 *   neighboring_cell_index);
8315 *  
8316 *   const auto nof = cell->neighbor_of_neighbor(f);
8317 *  
8318 *   if (handler.is_slave_cell(neighboring_cell))
8319 *   {
8320 * @endcode
8321 *
8322 * index of the neighboring polytope
8323 *
8324 * @code
8326 *   neighbor_polytope_index =
8327 *   handler.master2polygon.at(
8328 *   master_of_neighbor->active_cell_index());
8329 *  
8330 *   CellId neighbor_polytope_id =
8331 *   master_of_neighbor->id();
8332 *  
8333 *   if (visited_polygonal_neighbors.find(
8334 *   neighbor_polytope_index) ==
8335 *   std::end(visited_polygonal_neighbors))
8336 *   {
8337 * @endcode
8338 *
8339 * found a neighbor
8340 *
8341
8342 *
8343 *
8344 * @code
8345 *   const unsigned int n_face =
8346 *   handler.number_of_agglomerated_faces
8347 *   [current_polytope_index];
8348 *  
8349 *   handler.polytope_cache.cell_face_at_boundary[{
8350 *   current_polytope_index, n_face}] = {
8351 *   false, master_of_neighbor};
8352 *  
8353 *   is_face_at_boundary[n_face] = true;
8354 *  
8355 *   ++handler.number_of_agglomerated_faces
8356 *   [current_polytope_index];
8357 *  
8358 *   visited_polygonal_neighbors.insert(
8359 *   neighbor_polytope_index);
8360 *   }
8361 *  
8362 *  
8363 *   if (handler.polytope_cache.visited_cell_and_faces
8364 *   .find({cell_index, f}) ==
8365 *   std::end(handler.polytope_cache
8366 *   .visited_cell_and_faces))
8367 *   {
8368 *   handler.polytope_cache
8369 *   .interface[{current_polytope_id,
8370 *   neighbor_polytope_id}]
8371 *   .emplace_back(cell, f);
8372 *  
8373 *   handler.polytope_cache.visited_cell_and_faces
8374 *   .insert({cell_index, f});
8375 *   }
8376 *  
8377 *  
8378 *   if (handler.polytope_cache.visited_cell_and_faces
8379 *   .find({neighboring_cell_index, nof}) ==
8380 *   std::end(handler.polytope_cache
8381 *   .visited_cell_and_faces))
8382 *   {
8383 *   handler.polytope_cache
8384 *   .interface[{neighbor_polytope_id,
8385 *   current_polytope_id}]
8386 *   .emplace_back(neighboring_cell, nof);
8387 *  
8388 *   handler.polytope_cache.visited_cell_and_faces
8389 *   .insert({neighboring_cell_index, nof});
8390 *   }
8391 *   }
8392 *   else
8393 *   {
8394 * @endcode
8395 *
8396 * neighboring cell is a master
8397 *
8398
8399 *
8400 * save the pair of neighboring cells
8401 *
8402 * @code
8404 *   neighbor_polytope_index =
8405 *   handler.master2polygon.at(
8406 *   neighboring_cell_index);
8407 *  
8408 *   CellId neighbor_polytope_id =
8409 *   neighboring_cell->id();
8410 *  
8411 *   if (visited_polygonal_neighbors.find(
8412 *   neighbor_polytope_index) ==
8413 *   std::end(visited_polygonal_neighbors))
8414 *   {
8415 * @endcode
8416 *
8417 * found a neighbor
8418 *
8419 * @code
8420 *   const unsigned int n_face =
8421 *   handler.number_of_agglomerated_faces
8422 *   [current_polytope_index];
8423 *  
8424 *  
8425 *   handler.polytope_cache.cell_face_at_boundary[{
8426 *   current_polytope_index, n_face}] = {
8427 *   false, neighboring_cell};
8428 *  
8429 *   is_face_at_boundary[n_face] = true;
8430 *  
8431 *   ++handler.number_of_agglomerated_faces
8432 *   [current_polytope_index];
8433 *  
8434 *   visited_polygonal_neighbors.insert(
8435 *   neighbor_polytope_index);
8436 *   }
8437 *  
8438 *  
8439 *  
8440 *   if (handler.polytope_cache.visited_cell_and_faces
8441 *   .find({cell_index, f}) ==
8442 *   std::end(handler.polytope_cache
8443 *   .visited_cell_and_faces))
8444 *   {
8445 *   handler.polytope_cache
8446 *   .interface[{current_polytope_id,
8447 *   neighbor_polytope_id}]
8448 *   .emplace_back(cell, f);
8449 *  
8450 *   handler.polytope_cache.visited_cell_and_faces
8451 *   .insert({cell_index, f});
8452 *   }
8453 *  
8454 *   if (handler.polytope_cache.visited_cell_and_faces
8455 *   .find({neighboring_cell_index, nof}) ==
8456 *   std::end(handler.polytope_cache
8457 *   .visited_cell_and_faces))
8458 *   {
8459 *   handler.polytope_cache
8460 *   .interface[{neighbor_polytope_id,
8461 *   current_polytope_id}]
8462 *   .emplace_back(neighboring_cell, nof);
8463 *  
8464 *   handler.polytope_cache.visited_cell_and_faces
8465 *   .insert({neighboring_cell_index, nof});
8466 *   }
8467 *   }
8468 *   }
8469 *   else if (neighboring_cell->is_ghost())
8470 *   {
8471 *   const auto nof = cell->neighbor_of_neighbor(f);
8472 *  
8473 * @endcode
8474 *
8475 * from neighboring rank,receive the association
8476 * between standard cell ids and neighboring polytope.
8477 * This tells to the current rank that the
8478 * neighboring cell has the following CellId as master
8479 * cell.
8480 *
8481 * @code
8482 *   const auto &check_neigh_poly_ids =
8483 *   handler.recv_cell_ids_neigh_cell.at(
8484 *   neighboring_cell->subdomain_id());
8485 *  
8486 *   const CellId neighboring_cell_id =
8487 *   neighboring_cell->id();
8488 *  
8489 *   const CellId &check_neigh_polytope_id =
8490 *   check_neigh_poly_ids.at(neighboring_cell_id);
8491 *  
8492 * @endcode
8493 *
8494 * const auto master_index =
8495 * master_indices[ghost_counter];
8496 *
8497
8498 *
8499 *
8500 * @code
8501 *   if (visited_polygonal_neighbors_id.find(
8502 *   check_neigh_polytope_id) ==
8503 *   std::end(visited_polygonal_neighbors_id))
8504 *   {
8505 *   handler.polytope_cache.cell_face_at_boundary[{
8506 *   current_polytope_index,
8507 *   handler.number_of_agglomerated_faces
8508 *   [current_polytope_index]}] = {false,
8509 *   neighboring_cell};
8510 *  
8511 *  
8512 * @endcode
8513 *
8514 * record the cell id of the neighboring polytope
8515 *
8516 * @code
8517 *   handler.polytope_cache.ghosted_master_id[{
8518 *   current_polytope_id,
8519 *   handler.number_of_agglomerated_faces
8520 *   [current_polytope_index]}] =
8521 *   check_neigh_polytope_id;
8522 *  
8523 *  
8524 *   const unsigned int n_face =
8525 *   handler.number_of_agglomerated_faces
8526 *   [current_polytope_index];
8527 *  
8528 *   face_to_neigh_id[n_face] = check_neigh_polytope_id;
8529 *  
8530 *   is_face_at_boundary[n_face] = false;
8531 *  
8532 *  
8533 * @endcode
8534 *
8535 * increment number of faces
8536 *
8537 * @code
8538 *   ++handler.number_of_agglomerated_faces
8539 *   [current_polytope_index];
8540 *  
8541 *   visited_polygonal_neighbors_id.insert(
8542 *   check_neigh_polytope_id);
8543 *  
8544 * @endcode
8545 *
8546 * ghosted polytope has been found, increment
8547 * ghost counter
8548 *
8549 * @code
8550 *   ++ghost_counter;
8551 *   }
8552 *  
8553 *  
8554 *  
8555 *   if (handler.polytope_cache.visited_cell_and_faces_id
8556 *   .find({cell_id, f}) ==
8557 *   std::end(
8558 *   handler.polytope_cache.visited_cell_and_faces_id))
8559 *   {
8560 *   handler.polytope_cache
8561 *   .interface[{current_polytope_id,
8562 *   check_neigh_polytope_id}]
8563 *   .emplace_back(cell, f);
8564 *  
8565 * @endcode
8566 *
8567 * std::cout << "ADDED ("
8568 * << cell->active_cell_index() << ")
8569 * BETWEEN "
8570 * << current_polytope_id << " e "
8571 * << check_neigh_polytope_id <<
8572 * std::endl;
8573 *
8574
8575 *
8576 *
8577 * @code
8578 *   handler.polytope_cache.visited_cell_and_faces_id
8579 *   .insert({cell_id, f});
8580 *   }
8581 *  
8582 *  
8583 *   if (handler.polytope_cache.visited_cell_and_faces_id
8584 *   .find({neighboring_cell_id, nof}) ==
8585 *   std::end(
8586 *   handler.polytope_cache.visited_cell_and_faces_id))
8587 *   {
8588 *   handler.polytope_cache
8589 *   .interface[{check_neigh_polytope_id,
8590 *   current_polytope_id}]
8591 *   .emplace_back(neighboring_cell, nof);
8592 *  
8593 *   handler.polytope_cache.visited_cell_and_faces_id
8594 *   .insert({neighboring_cell_id, nof});
8595 *   }
8596 *   }
8597 *   }
8598 *   else if (cell->face(f)->at_boundary())
8599 *   {
8600 * @endcode
8601 *
8602 * Boundary face of a boundary cell.
8603 * Note that the neighboring cell must be invalid.
8604 *
8605
8606 *
8607 *
8608 * @code
8609 *   handler.polygon_boundary[master_cell].push_back(
8610 *   cell->face(f));
8611 *  
8612 *   if (visited_polygonal_neighbors.find(
8613 *   std::numeric_limits<unsigned int>::max()) ==
8614 *   std::end(visited_polygonal_neighbors))
8615 *   {
8616 * @endcode
8617 *
8618 * boundary face. Notice that `neighboring_cell` is
8619 * invalid here.
8620 *
8621 * @code
8622 *   handler.polytope_cache.cell_face_at_boundary[{
8623 *   current_polytope_index,
8624 *   handler.number_of_agglomerated_faces
8625 *   [current_polytope_index]}] = {true,
8626 *   neighboring_cell};
8627 *  
8628 *   const unsigned int n_face =
8629 *   handler.number_of_agglomerated_faces
8630 *   [current_polytope_index];
8631 *  
8632 *   is_face_at_boundary[n_face] = true;
8633 *  
8634 *   ++handler.number_of_agglomerated_faces
8635 *   [current_polytope_index];
8636 *  
8637 *   visited_polygonal_neighbors.insert(
8638 *   std::numeric_limits<unsigned int>::max());
8639 *   }
8640 *  
8641 *  
8642 *  
8643 *   if (handler.polytope_cache.visited_cell_and_faces.find(
8644 *   {cell_index, f}) ==
8645 *   std::end(handler.polytope_cache.visited_cell_and_faces))
8646 *   {
8647 *   handler.polytope_cache
8648 *   .interface[{current_polytope_id, current_polytope_id}]
8649 *   .emplace_back(cell, f);
8650 *  
8651 *   handler.polytope_cache.visited_cell_and_faces.insert(
8652 *   {cell_index, f});
8653 *   }
8654 *   }
8655 *   } // loop over faces
8656 *   } // loop over all cells of agglomerate
8657 *  
8658 *  
8659 *  
8660 *   if (ghost_counter > 0)
8661 *   {
8662 *   const auto parallel_triangulation = dynamic_cast<
8663 *   const ::parallel::TriangulationBase<dim, spacedim> *>(
8664 *   &(*handler.tria));
8665 *  
8666 *   const unsigned int n_faces_current_poly =
8667 *   handler.number_of_agglomerated_faces[current_polytope_index];
8668 *  
8669 * @endcode
8670 *
8671 * Communicate to neighboring ranks that current_polytope_id has
8672 * a number of faces equal to n_faces_current_poly faces:
8673 * current_polytope_id -> n_faces_current_poly
8674 *
8675 * @code
8676 *   for (const unsigned int neigh_rank :
8677 *   parallel_triangulation->ghost_owners())
8678 *   {
8679 *   handler.local_n_faces[neigh_rank].emplace(current_polytope_id,
8680 *   n_faces_current_poly);
8681 *  
8682 *   handler.local_bdary_info[neigh_rank].emplace(
8683 *   current_polytope_id, is_face_at_boundary);
8684 *  
8685 *   handler.local_ghosted_master_id[neigh_rank].emplace(
8686 *   current_polytope_id, face_to_neigh_id);
8687 *   }
8688 *   }
8689 *   }
8690 *   };
8691 *  
8692 *  
8693 *  
8694 *   } // namespace internal
8695 *   } // namespace dealii
8696 *  
8697 *  
8698 *  
8699 *   template class AgglomerationHandler<1>;
8700 *   template void
8701 *   AgglomerationHandler<1>::create_agglomeration_sparsity_pattern(
8702 *   DynamicSparsityPattern &sparsity_pattern,
8703 *   const AffineConstraints<double> &constraints,
8704 *   const bool keep_constrained_dofs,
8705 *   const types::subdomain_id subdomain_id);
8706 *  
8707 *   template void
8708 *   AgglomerationHandler<1>::create_agglomeration_sparsity_pattern(
8709 *   TrilinosWrappers::SparsityPattern &sparsity_pattern,
8710 *   const AffineConstraints<double> &constraints,
8711 *   const bool keep_constrained_dofs,
8712 *   const types::subdomain_id subdomain_id);
8713 *  
8714 *   template class AgglomerationHandler<2>;
8715 *   template void
8716 *   AgglomerationHandler<2>::create_agglomeration_sparsity_pattern(
8717 *   DynamicSparsityPattern &sparsity_pattern,
8718 *   const AffineConstraints<double> &constraints,
8719 *   const bool keep_constrained_dofs,
8720 *   const types::subdomain_id subdomain_id);
8721 *  
8722 *   template void
8723 *   AgglomerationHandler<2>::create_agglomeration_sparsity_pattern(
8724 *   TrilinosWrappers::SparsityPattern &sparsity_pattern,
8725 *   const AffineConstraints<double> &constraints,
8726 *   const bool keep_constrained_dofs,
8727 *   const types::subdomain_id subdomain_id);
8728 *  
8729 *   template class AgglomerationHandler<3>;
8730 *   template void
8731 *   AgglomerationHandler<3>::create_agglomeration_sparsity_pattern(
8732 *   DynamicSparsityPattern &sparsity_pattern,
8733 *   const AffineConstraints<double> &constraints,
8734 *   const bool keep_constrained_dofs,
8735 *   const types::subdomain_id subdomain_id);
8736 *  
8737 *   template void
8738 *   AgglomerationHandler<3>::create_agglomeration_sparsity_pattern(
8739 *   TrilinosWrappers::SparsityPattern &sparsity_pattern,
8740 *   const AffineConstraints<double> &constraints,
8741 *   const bool keep_constrained_dofs,
8742 *   const types::subdomain_id subdomain_id);
8743 * @endcode
8744
8745
8746<a name="ann-source/mapping_box.cc"></a>
8747<h1>Annotated version of source/mapping_box.cc</h1>
8748 *
8749 *
8750 *
8751 *
8752 * @code
8753 *   /* -----------------------------------------------------------------------------
8754 *   *
8755 *   * SPDX-License-Identifier: LGPL-2.1-or-later
8756 *   * Copyright (C) 2025 by Marco Feder, Pasquale Claudio Africa, Xinping Gui,
8757 *   * Andrea Cangiani
8758 *   *
8759 *   * This file is part of the deal.II code gallery.
8760 *   *
8761 *   * -----------------------------------------------------------------------------
8762 *   */
8763 *  
8764 *   #include <deal.II/base/array_view.h>
8765 *   #include <deal.II/base/memory_consumption.h>
8766 *   #include <deal.II/base/qprojector.h>
8767 *   #include <deal.II/base/quadrature.h>
8768 *   #include <deal.II/base/signaling_nan.h>
8769 *   #include <deal.II/base/tensor.h>
8770 *  
8771 *   #include <deal.II/dofs/dof_accessor.h>
8772 *  
8773 *   #include <deal.II/fe/fe_values.h>
8774 *  
8775 *   #include <deal.II/grid/tria.h>
8776 *   #include <deal.II/grid/tria_iterator.h>
8777 *  
8778 *   #include <deal.II/lac/full_matrix.h>
8779 *  
8780 *   #include <mapping_box.h>
8781 *  
8782 *   #include <algorithm>
8783 *  
8785 *  
8787 *   ExcCellNotAssociatedWithBox,
8788 *   "You are using MappingBox, but the incoming element is not associated with a"
8789 *   "Bounding Box Cartesian.");
8790 *  
8791 *  
8792 *  
8793 *  
8797 *   template <typename CellType>
8798 *   bool
8799 *   has_box(const CellType &cell,
8800 *   const std::map<types::global_cell_index, types::global_cell_index>
8801 *   &translator)
8802 *   {
8803 *   Assert((cell->reference_cell().is_hyper_cube() ||
8804 *   cell->reference_cell().is_simplex()),
8805 *   ExcNotImplemented());
8806 *   Assert((translator.find(cell->active_cell_index()) != translator.cend()),
8807 *   ExcCellNotAssociatedWithBox());
8808 *  
8809 *   return true;
8810 *   }
8811 *  
8812 *  
8813 *  
8814 *   template <int dim, int spacedim>
8815 *   MappingBox<dim, spacedim>::MappingBox(
8816 *   const std::vector<BoundingBox<dim>> &input_boxes,
8817 *   const std::map<types::global_cell_index, types::global_cell_index>
8818 *   &global_to_polytope)
8819 *   {
8820 *   Assert(input_boxes.size() > 0,
8821 *   ExcMessage("Invalid number of bounding boxes."));
8822 *  
8823 * @endcode
8824 *
8825 * copy boxes and map
8826 *
8827 * @code
8828 *   boxes.resize(input_boxes.size());
8829 *   for (unsigned int i = 0; i < input_boxes.size(); ++i)
8830 *   boxes[i] = input_boxes[i];
8831 *   polytope_translator = global_to_polytope;
8832 *   }
8833 *  
8834 *  
8835 *  
8836 *   template <int dim, int spacedim>
8837 *   MappingBox<dim, spacedim>::InternalData::InternalData(const Quadrature<dim> &q)
8838 *   : cell_extents(numbers::signaling_nan<Tensor<1, dim>>())
8839 *   , traslation(numbers::signaling_nan<Tensor<1, dim>>())
8840 *   , inverse_cell_extents(numbers::signaling_nan<Tensor<1, dim>>())
8841 *   , volume_element(numbers::signaling_nan<double>())
8842 *   , quadrature_points(q.get_points())
8843 *   {}
8844 *  
8845 *  
8846 *  
8847 *   template <int dim, int spacedim>
8848 *   void
8849 *   MappingBox<dim, spacedim>::InternalData::reinit(const UpdateFlags update_flags,
8850 *   const Quadrature<dim> &)
8851 *   {
8852 * @endcode
8853 *
8854 * store the flags in the internal data object so we can access them
8855 * in fill_fe_*_values(). use the transitive hull of the required
8856 * flags
8857 *
8858 * @code
8859 *   this->update_each = update_flags;
8860 *   }
8861 *  
8862 *  
8863 *  
8864 *   template <int dim, int spacedim>
8865 *   std::size_t
8866 *   MappingBox<dim, spacedim>::InternalData::memory_consumption() const
8867 *   {
8871 *   MemoryConsumption::memory_consumption(inverse_cell_extents) +
8872 *   MemoryConsumption::memory_consumption(volume_element));
8873 *   }
8874 *  
8875 *  
8876 *  
8877 *   template <int dim, int spacedim>
8878 *   bool
8879 *   MappingBox<dim, spacedim>::preserves_vertex_locations() const
8880 *   {
8881 *   return true;
8882 *   }
8883 *  
8884 *  
8885 *  
8886 *   template <int dim, int spacedim>
8887 *   bool
8888 *   MappingBox<dim, spacedim>::is_compatible_with(
8889 *   #if DEAL_II_VERSION_GTE(9, 8, 0)
8890 *   const ReferenceCell<dim> &reference_cell
8891 *   #else
8892 *   const ReferenceCell &reference_cell
8893 *   #endif
8894 *   ) const
8895 *   {
8896 *   Assert(dim == reference_cell.get_dimension(),
8897 *   ExcMessage("The dimension of your mapping (" +
8898 *   Utilities::to_string(dim) +
8899 *   ") and the reference cell cell_type (" +
8900 *   Utilities::to_string(reference_cell.get_dimension()) +
8901 *   " ) do not agree."));
8902 *  
8903 *   return reference_cell.is_hyper_cube() || reference_cell.is_simplex();
8904 *   }
8905 *  
8906 *  
8907 *  
8908 *   template <int dim, int spacedim>
8909 *   UpdateFlags
8910 *   MappingBox<dim, spacedim>::requires_update_flags(const UpdateFlags in) const
8911 *   {
8912 * @endcode
8913 *
8914 * this mapping is pretty simple in that it can basically compute
8915 * every piece of information wanted by FEValues without requiring
8916 * computing any other quantities. boundary forms are one exception
8917 * since they can be computed from the normal vectors without much
8918 * further ado
8919 *
8920 * @code
8921 *   UpdateFlags out = in;
8922 *   if (out & update_boundary_forms)
8923 *   out |= update_normal_vectors;
8924 *  
8925 *   return out;
8926 *   }
8927 *  
8928 *  
8929 *  
8930 *   template <int dim, int spacedim>
8931 *   std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
8932 *   MappingBox<dim, spacedim>::get_data(const UpdateFlags update_flags,
8933 *   const Quadrature<dim> &q) const
8934 *   {
8935 *   std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase> data_ptr =
8936 *   std::make_unique<InternalData>();
8937 *   data_ptr->reinit(requires_update_flags(update_flags), q);
8938 *  
8939 *   return data_ptr;
8940 *   }
8941 *  
8942 *  
8943 *  
8944 *   template <int dim, int spacedim>
8945 *   std::unique_ptr<typename Mapping<dim, spacedim>::InternalDataBase>
8946 *   MappingBox<dim, spacedim>::get_subface_data(
8947 *   const UpdateFlags update_flags,
8948 *   const Quadrature<dim - 1> &quadrature) const
8949 *   {
8950 *   (void)update_flags;
8951 *   (void)quadrature;
8953 *   return {};
8954 *   }
8955 *  
8956 *  
8957 *  
8958 *   template <int dim, int spacedim>
8959 *   void
8960 *   MappingBox<dim, spacedim>::update_cell_extents(
8961 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
8962 *   const CellSimilarity::Similarity cell_similarity,
8963 *   const InternalData &data) const
8964 *   {
8965 * @endcode
8966 *
8967 * Compute start point and sizes along axes. The vertices to be looked at
8968 * are 1, 2, 4 compared to the base vertex 0.
8969 *
8970 * @code
8971 *   if (cell_similarity != CellSimilarity::translation)
8972 *   {
8973 *   const BoundingBox<dim> &current_box =
8974 *   boxes[polytope_translator.at(cell->active_cell_index())];
8975 *   const std::pair<Point<dim>, Point<dim>> &bdary_points =
8976 *   current_box.get_boundary_points();
8977 *  
8978 *   for (unsigned int d = 0; d < dim; ++d)
8979 *   {
8980 *   const double cell_extent_d = current_box.side_length(d);
8981 *   data.cell_extents[d] = cell_extent_d;
8982 *  
8983 *   data.traslation[d] =
8984 *   .5 * (bdary_points.first[d] +
8985 *   bdary_points.second[d]); // midpoint of each interval
8986 *  
8987 *   Assert(cell_extent_d != 0.,
8988 *   ExcMessage("Cell does not appear to be Cartesian!"));
8989 *   data.inverse_cell_extents[d] = 1. / cell_extent_d;
8990 *   }
8991 *   }
8992 *   }
8993 *  
8994 *  
8995 *  
8996 *   namespace
8997 *   {
8998 *   template <int dim>
8999 *   void
9000 *   transform_quadrature_points(
9001 *   const BoundingBox<dim> &box,
9002 *   const ArrayView<const Point<dim>> &unit_quadrature_points,
9003 *   std::vector<Point<dim>> &quadrature_points)
9004 *   {
9005 *   for (unsigned int i = 0; i < quadrature_points.size(); ++i)
9006 *   quadrature_points[i] = box.unit_to_real(unit_quadrature_points[i]);
9007 *   }
9008 *   } // namespace
9009 *  
9010 *  
9011 *  
9012 *   template <int dim, int spacedim>
9013 *   void
9014 *   MappingBox<dim, spacedim>::maybe_update_cell_quadrature_points(
9015 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9016 *   const InternalData &data,
9017 *   const ArrayView<const Point<dim>> &unit_quadrature_points,
9018 *   std::vector<Point<dim>> &quadrature_points) const
9019 *   {
9020 *   if (data.update_each & update_quadrature_points)
9021 *   transform_quadrature_points(
9022 *   boxes[polytope_translator.at(cell->active_cell_index())],
9023 *   unit_quadrature_points,
9024 *   quadrature_points);
9025 *   }
9026 *  
9027 *  
9028 *  
9029 *   template <int dim, int spacedim>
9030 *   void
9031 *   MappingBox<dim, spacedim>::maybe_update_normal_vectors(
9032 *   const unsigned int face_no,
9033 *   const InternalData &data,
9034 *   std::vector<Tensor<1, dim>> &normal_vectors) const
9035 *   {
9036 * @endcode
9037 *
9038 * compute normal vectors. All normals on a face have the same value.
9039 *
9040 * @code
9041 *   if (data.update_each & update_normal_vectors)
9042 *   {
9043 *   Assert(face_no < GeometryInfo<dim>::faces_per_cell, ExcInternalError());
9044 *   std::fill(normal_vectors.begin(),
9045 *   normal_vectors.end(),
9047 *   }
9048 *   }
9049 *  
9050 *  
9051 *  
9052 *   template <int dim, int spacedim>
9053 *   void
9054 *   MappingBox<dim, spacedim>::maybe_update_jacobian_derivatives(
9055 *   const InternalData &data,
9056 *   const CellSimilarity::Similarity cell_similarity,
9058 *   &output_data) const
9059 *   {
9060 *   if (cell_similarity != CellSimilarity::translation)
9061 *   {
9062 *   if (data.update_each & update_jacobian_grads)
9063 *   for (unsigned int i = 0; i < output_data.jacobian_grads.size(); ++i)
9064 *   output_data.jacobian_grads[i] = DerivativeForm<2, dim, spacedim>();
9065 *  
9066 *   if (data.update_each & update_jacobian_pushed_forward_grads)
9067 *   for (unsigned int i = 0;
9068 *   i < output_data.jacobian_pushed_forward_grads.size();
9069 *   ++i)
9070 *   output_data.jacobian_pushed_forward_grads[i] = Tensor<3, spacedim>();
9071 *  
9072 *   if (data.update_each & update_jacobian_2nd_derivatives)
9073 *   for (unsigned int i = 0;
9074 *   i < output_data.jacobian_2nd_derivatives.size();
9075 *   ++i)
9076 *   output_data.jacobian_2nd_derivatives[i] =
9078 *  
9080 *   for (unsigned int i = 0;
9081 *   i < output_data.jacobian_pushed_forward_2nd_derivatives.size();
9082 *   ++i)
9083 *   output_data.jacobian_pushed_forward_2nd_derivatives[i] =
9085 *  
9086 *   if (data.update_each & update_jacobian_3rd_derivatives)
9087 *   for (unsigned int i = 0;
9088 *   i < output_data.jacobian_3rd_derivatives.size();
9089 *   ++i)
9090 *   output_data.jacobian_3rd_derivatives[i] =
9092 *  
9094 *   for (unsigned int i = 0;
9095 *   i < output_data.jacobian_pushed_forward_3rd_derivatives.size();
9096 *   ++i)
9097 *   output_data.jacobian_pushed_forward_3rd_derivatives[i] =
9099 *   }
9100 *   }
9101 *  
9102 *  
9103 *  
9104 *   template <int dim, int spacedim>
9105 *   void
9106 *   MappingBox<dim, spacedim>::maybe_update_volume_elements(
9107 *   const InternalData &data) const
9108 *   {
9109 *   if (data.update_each & update_volume_elements)
9110 *   {
9111 *   double volume = data.cell_extents[0];
9112 *   for (unsigned int d = 1; d < dim; ++d)
9113 *   volume *= data.cell_extents[d];
9114 *   data.volume_element = volume;
9115 *   }
9116 *   }
9117 *  
9118 *  
9119 *  
9120 *   template <int dim, int spacedim>
9121 *   void
9122 *   MappingBox<dim, spacedim>::maybe_update_jacobians(
9123 *   const InternalData &data,
9124 *   const CellSimilarity::Similarity cell_similarity,
9126 *   &output_data) const
9127 *   {
9128 * @endcode
9129 *
9130 * "compute" Jacobian at the quadrature points, which are all the
9131 * same
9132 *
9133 * @code
9134 *   if (data.update_each & update_jacobians)
9135 *   if (cell_similarity != CellSimilarity::translation)
9136 *   for (unsigned int i = 0; i < output_data.jacobians.size(); ++i)
9137 *   {
9138 *   output_data.jacobians[i] = DerivativeForm<1, dim, spacedim>();
9139 *   for (unsigned int j = 0; j < dim; ++j)
9140 *   output_data.jacobians[i][j][j] = data.cell_extents[j];
9141 *   }
9142 *   }
9143 *  
9144 *  
9145 *  
9146 *   template <int dim, int spacedim>
9147 *   void
9148 *   MappingBox<dim, spacedim>::maybe_update_inverse_jacobians(
9149 *   const InternalData &data,
9150 *   const CellSimilarity::Similarity cell_similarity,
9152 *   &output_data) const
9153 *   {
9154 * @endcode
9155 *
9156 * "compute" inverse Jacobian at the quadrature points, which are
9157 * all the same
9158 *
9159 * @code
9160 *   if (data.update_each & update_inverse_jacobians)
9161 *   if (cell_similarity != CellSimilarity::translation)
9162 *   for (unsigned int i = 0; i < output_data.inverse_jacobians.size(); ++i)
9163 *   {
9164 *   output_data.inverse_jacobians[i] = Tensor<2, dim>();
9165 *   for (unsigned int j = 0; j < dim; ++j)
9166 *   output_data.inverse_jacobians[i][j][j] =
9167 *   data.inverse_cell_extents[j];
9168 *   }
9169 *   }
9170 *  
9171 *  
9172 *  
9173 *   template <int dim, int spacedim>
9175 *   MappingBox<dim, spacedim>::fill_fe_values(
9176 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9177 *   const CellSimilarity::Similarity cell_similarity,
9178 *   const Quadrature<dim> &quadrature,
9179 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
9181 *   &output_data) const
9182 *   {
9183 *   Assert(has_box(cell, polytope_translator), ExcCellNotAssociatedWithBox());
9184 *  
9185 * @endcode
9186 *
9187 * convert data object to internal data for this class. fails with
9188 * an exception if that is not possible
9189 *
9190 * @code
9191 *   Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
9192 *   ExcInternalError());
9193 *   const InternalData &data = static_cast<const InternalData &>(internal_data);
9194 *  
9195 *  
9196 *   update_cell_extents(cell, cell_similarity, data);
9197 *  
9198 *   maybe_update_cell_quadrature_points(cell,
9199 *   data,
9200 *   quadrature.get_points(),
9201 *   output_data.quadrature_points);
9202 *  
9203 * @endcode
9204 *
9205 * compute Jacobian determinant. all values are equal and are the
9206 * product of the local lengths in each coordinate direction
9207 *
9208 * @code
9209 *   if (data.update_each & (update_JxW_values | update_volume_elements))
9210 *   if (cell_similarity != CellSimilarity::translation)
9211 *   {
9212 *   double J = data.cell_extents[0];
9213 *   for (unsigned int d = 1; d < dim; ++d)
9214 *   J *= data.cell_extents[d];
9215 *   data.volume_element = J;
9216 *   if (data.update_each & update_JxW_values)
9217 *   for (unsigned int i = 0; i < output_data.JxW_values.size(); ++i)
9218 *   output_data.JxW_values[i] = quadrature.weight(i);
9219 *   }
9220 *  
9221 *  
9222 *   maybe_update_jacobians(data, cell_similarity, output_data);
9223 *   maybe_update_jacobian_derivatives(data, cell_similarity, output_data);
9224 *   maybe_update_inverse_jacobians(data, cell_similarity, output_data);
9225 *  
9226 *   return cell_similarity;
9227 *   }
9228 *  
9229 *  
9230 *  
9231 *   template <int dim, int spacedim>
9232 *   void
9233 *   MappingBox<dim, spacedim>::fill_fe_subface_values(
9234 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9235 *   const unsigned int face_no,
9236 *   const unsigned int subface_no,
9237 *   const Quadrature<dim - 1> &quadrature,
9238 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
9240 *   &output_data) const
9241 *   {
9242 *   (void)cell;
9243 *   (void)face_no;
9244 *   (void)subface_no;
9245 *   (void)quadrature;
9246 *   (void)internal_data;
9247 *   (void)output_data;
9249 *   }
9250 *  
9251 *  
9252 *  
9253 *   template <int dim, int spacedim>
9254 *   void
9255 *   MappingBox<dim, spacedim>::fill_fe_immersed_surface_values(
9256 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9258 *   const typename Mapping<dim, spacedim>::InternalDataBase &internal_data,
9260 *   &output_data) const
9261 *   {
9262 *   AssertDimension(dim, spacedim);
9263 *   Assert(has_box(cell, polytope_translator), ExcCellNotAssociatedWithBox());
9264 *  
9265 * @endcode
9266 *
9267 * Convert data object to internal data for this class. Fails with an
9268 * exception if that is not possible.
9269 *
9270 * @code
9271 *   Assert(dynamic_cast<const InternalData *>(&internal_data) != nullptr,
9272 *   ExcInternalError());
9273 *   const InternalData &data = static_cast<const InternalData &>(internal_data);
9274 *  
9275 *  
9276 *   update_cell_extents(cell, CellSimilarity::none, data);
9277 *  
9278 *   maybe_update_cell_quadrature_points(cell,
9279 *   data,
9280 *   quadrature.get_points(),
9281 *   output_data.quadrature_points);
9282 *  
9283 *   if (data.update_each & update_normal_vectors)
9284 *   for (unsigned int i = 0; i < output_data.normal_vectors.size(); ++i)
9285 *   output_data.normal_vectors[i] = quadrature.normal_vector(i);
9286 *  
9287 *   if (data.update_each & update_JxW_values)
9288 *   for (unsigned int i = 0; i < output_data.JxW_values.size(); ++i)
9289 *   output_data.JxW_values[i] = quadrature.weight(i);
9290 *  
9291 *   maybe_update_volume_elements(data);
9292 *   maybe_update_jacobians(data, CellSimilarity::none, output_data);
9293 *   maybe_update_jacobian_derivatives(data, CellSimilarity::none, output_data);
9294 *   maybe_update_inverse_jacobians(data, CellSimilarity::none, output_data);
9295 *   }
9296 *  
9297 *  
9298 *  
9299 *   template <int dim, int spacedim>
9300 *   void
9301 *   MappingBox<dim, spacedim>::transform(
9302 *   const ArrayView<const Tensor<1, dim>> &input,
9303 *   const MappingKind mapping_kind,
9304 *   const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
9305 *   const ArrayView<Tensor<1, spacedim>> &output) const
9306 *   {
9307 *   AssertDimension(input.size(), output.size());
9308 *   Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
9309 *   ExcInternalError());
9310 *   const InternalData &data = static_cast<const InternalData &>(mapping_data);
9311 *  
9312 *   switch (mapping_kind)
9313 *   {
9314 *   case mapping_covariant:
9315 *   {
9318 *   "update_covariant_transformation"));
9319 *  
9320 *   for (unsigned int i = 0; i < output.size(); ++i)
9321 *   for (unsigned int d = 0; d < dim; ++d)
9322 *   output[i][d] = input[i][d] * data.inverse_cell_extents[d];
9323 *   return;
9324 *   }
9325 *  
9327 *   {
9330 *   "update_contravariant_transformation"));
9331 *  
9332 *   for (unsigned int i = 0; i < output.size(); ++i)
9333 *   for (unsigned int d = 0; d < dim; ++d)
9334 *   output[i][d] = input[i][d] * data.cell_extents[d];
9335 *   return;
9336 *   }
9337 *   case mapping_piola:
9338 *   {
9341 *   "update_contravariant_transformation"));
9342 *   Assert(data.update_each & update_volume_elements,
9344 *   "update_volume_elements"));
9345 *  
9346 *   for (unsigned int i = 0; i < output.size(); ++i)
9347 *   for (unsigned int d = 0; d < dim; ++d)
9348 *   output[i][d] =
9349 *   input[i][d] * data.cell_extents[d] / data.volume_element;
9350 *   return;
9351 *   }
9352 *   default:
9354 *   }
9355 *   }
9356 *  
9357 *  
9358 *  
9359 *   template <int dim, int spacedim>
9360 *   void
9361 *   MappingBox<dim, spacedim>::transform(
9362 *   const ArrayView<const DerivativeForm<1, dim, spacedim>> &input,
9363 *   const MappingKind mapping_kind,
9364 *   const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
9365 *   const ArrayView<Tensor<2, spacedim>> &output) const
9366 *   {
9367 *   AssertDimension(input.size(), output.size());
9368 *   Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
9369 *   ExcInternalError());
9370 *   const InternalData &data = static_cast<const InternalData &>(mapping_data);
9371 *  
9372 *   switch (mapping_kind)
9373 *   {
9374 *   case mapping_covariant:
9375 *   {
9378 *   "update_covariant_transformation"));
9379 *  
9380 *   for (unsigned int i = 0; i < output.size(); ++i)
9381 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9382 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9383 *   output[i][d1][d2] =
9384 *   input[i][d1][d2] * data.inverse_cell_extents[d2];
9385 *   return;
9386 *   }
9387 *  
9389 *   {
9392 *   "update_contravariant_transformation"));
9393 *  
9394 *   for (unsigned int i = 0; i < output.size(); ++i)
9395 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9396 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9397 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2];
9398 *   return;
9399 *   }
9400 *  
9402 *   {
9405 *   "update_covariant_transformation"));
9406 *  
9407 *   for (unsigned int i = 0; i < output.size(); ++i)
9408 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9409 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9410 *   output[i][d1][d2] = input[i][d1][d2] *
9411 *   data.inverse_cell_extents[d2] *
9412 *   data.inverse_cell_extents[d1];
9413 *   return;
9414 *   }
9415 *  
9417 *   {
9420 *   "update_contravariant_transformation"));
9421 *  
9422 *   for (unsigned int i = 0; i < output.size(); ++i)
9423 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9424 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9425 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] *
9426 *   data.inverse_cell_extents[d1];
9427 *   return;
9428 *   }
9429 *  
9430 *   case mapping_piola:
9431 *   {
9434 *   "update_contravariant_transformation"));
9435 *   Assert(data.update_each & update_volume_elements,
9437 *   "update_volume_elements"));
9438 *  
9439 *   for (unsigned int i = 0; i < output.size(); ++i)
9440 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9441 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9442 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] /
9443 *   data.volume_element;
9444 *   return;
9445 *   }
9446 *  
9448 *   {
9451 *   "update_contravariant_transformation"));
9452 *   Assert(data.update_each & update_volume_elements,
9454 *   "update_volume_elements"));
9455 *  
9456 *   for (unsigned int i = 0; i < output.size(); ++i)
9457 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9458 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9459 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] *
9460 *   data.inverse_cell_extents[d1] /
9461 *   data.volume_element;
9462 *   return;
9463 *   }
9464 *  
9465 *   default:
9467 *   }
9468 *   }
9469 *  
9470 *  
9471 *  
9472 *   template <int dim, int spacedim>
9473 *   void
9474 *   MappingBox<dim, spacedim>::transform(
9475 *   const ArrayView<const Tensor<2, dim>> &input,
9476 *   const MappingKind mapping_kind,
9477 *   const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
9478 *   const ArrayView<Tensor<2, spacedim>> &output) const
9479 *   {
9480 *   AssertDimension(input.size(), output.size());
9481 *   Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
9482 *   ExcInternalError());
9483 *   const InternalData &data = static_cast<const InternalData &>(mapping_data);
9484 *  
9485 *   switch (mapping_kind)
9486 *   {
9487 *   case mapping_covariant:
9488 *   {
9491 *   "update_covariant_transformation"));
9492 *  
9493 *   for (unsigned int i = 0; i < output.size(); ++i)
9494 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9495 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9496 *   output[i][d1][d2] =
9497 *   input[i][d1][d2] * data.inverse_cell_extents[d2];
9498 *   return;
9499 *   }
9500 *  
9502 *   {
9505 *   "update_contravariant_transformation"));
9506 *  
9507 *   for (unsigned int i = 0; i < output.size(); ++i)
9508 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9509 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9510 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2];
9511 *   return;
9512 *   }
9513 *  
9515 *   {
9518 *   "update_covariant_transformation"));
9519 *  
9520 *   for (unsigned int i = 0; i < output.size(); ++i)
9521 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9522 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9523 *   output[i][d1][d2] = input[i][d1][d2] *
9524 *   data.inverse_cell_extents[d2] *
9525 *   data.inverse_cell_extents[d1];
9526 *   return;
9527 *   }
9528 *  
9530 *   {
9533 *   "update_contravariant_transformation"));
9534 *  
9535 *   for (unsigned int i = 0; i < output.size(); ++i)
9536 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9537 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9538 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] *
9539 *   data.inverse_cell_extents[d1];
9540 *   return;
9541 *   }
9542 *  
9543 *   case mapping_piola:
9544 *   {
9547 *   "update_contravariant_transformation"));
9548 *   Assert(data.update_each & update_volume_elements,
9550 *   "update_volume_elements"));
9551 *  
9552 *   for (unsigned int i = 0; i < output.size(); ++i)
9553 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9554 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9555 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] /
9556 *   data.volume_element;
9557 *   return;
9558 *   }
9559 *  
9561 *   {
9564 *   "update_contravariant_transformation"));
9565 *   Assert(data.update_each & update_volume_elements,
9567 *   "update_volume_elements"));
9568 *  
9569 *   for (unsigned int i = 0; i < output.size(); ++i)
9570 *   for (unsigned int d1 = 0; d1 < dim; ++d1)
9571 *   for (unsigned int d2 = 0; d2 < dim; ++d2)
9572 *   output[i][d1][d2] = input[i][d1][d2] * data.cell_extents[d2] *
9573 *   data.inverse_cell_extents[d1] /
9574 *   data.volume_element;
9575 *   return;
9576 *   }
9577 *  
9578 *   default:
9580 *   }
9581 *   }
9582 *  
9583 *  
9584 *  
9585 *   template <int dim, int spacedim>
9586 *   void
9587 *   MappingBox<dim, spacedim>::transform(
9588 *   const ArrayView<const DerivativeForm<2, dim, spacedim>> &input,
9589 *   const MappingKind mapping_kind,
9590 *   const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
9591 *   const ArrayView<Tensor<3, spacedim>> &output) const
9592 *   {
9593 *   AssertDimension(input.size(), output.size());
9594 *   Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
9595 *   ExcInternalError());
9596 *   const InternalData &data = static_cast<const InternalData &>(mapping_data);
9597 *  
9598 *   switch (mapping_kind)
9599 *   {
9601 *   {
9604 *   "update_covariant_transformation"));
9605 *  
9606 *   for (unsigned int q = 0; q < output.size(); ++q)
9607 *   for (unsigned int i = 0; i < spacedim; ++i)
9608 *   for (unsigned int j = 0; j < spacedim; ++j)
9609 *   for (unsigned int k = 0; k < spacedim; ++k)
9610 *   {
9611 *   output[q][i][j][k] = input[q][i][j][k] *
9612 *   data.inverse_cell_extents[j] *
9613 *   data.inverse_cell_extents[k];
9614 *   }
9615 *   return;
9616 *   }
9617 *   default:
9619 *   }
9620 *   }
9621 *  
9622 *  
9623 *  
9624 *   template <int dim, int spacedim>
9625 *   void
9626 *   MappingBox<dim, spacedim>::transform(
9627 *   const ArrayView<const Tensor<3, dim>> &input,
9628 *   const MappingKind mapping_kind,
9629 *   const typename Mapping<dim, spacedim>::InternalDataBase &mapping_data,
9630 *   const ArrayView<Tensor<3, spacedim>> &output) const
9631 *   {
9632 *   AssertDimension(input.size(), output.size());
9633 *   Assert(dynamic_cast<const InternalData *>(&mapping_data) != nullptr,
9634 *   ExcInternalError());
9635 *   const InternalData &data = static_cast<const InternalData &>(mapping_data);
9636 *  
9637 *   switch (mapping_kind)
9638 *   {
9640 *   {
9643 *   "update_covariant_transformation"));
9646 *   "update_contravariant_transformation"));
9647 *  
9648 *   for (unsigned int q = 0; q < output.size(); ++q)
9649 *   for (unsigned int i = 0; i < spacedim; ++i)
9650 *   for (unsigned int j = 0; j < spacedim; ++j)
9651 *   for (unsigned int k = 0; k < spacedim; ++k)
9652 *   {
9653 *   output[q][i][j][k] = input[q][i][j][k] *
9654 *   data.cell_extents[i] *
9655 *   data.inverse_cell_extents[j] *
9656 *   data.inverse_cell_extents[k];
9657 *   }
9658 *   return;
9659 *   }
9660 *  
9662 *   {
9665 *   "update_covariant_transformation"));
9666 *  
9667 *   for (unsigned int q = 0; q < output.size(); ++q)
9668 *   for (unsigned int i = 0; i < spacedim; ++i)
9669 *   for (unsigned int j = 0; j < spacedim; ++j)
9670 *   for (unsigned int k = 0; k < spacedim; ++k)
9671 *   {
9672 *   output[q][i][j][k] = input[q][i][j][k] *
9673 *   (data.inverse_cell_extents[i] *
9674 *   data.inverse_cell_extents[j]) *
9675 *   data.inverse_cell_extents[k];
9676 *   }
9677 *  
9678 *   return;
9679 *   }
9680 *  
9682 *   {
9685 *   "update_covariant_transformation"));
9688 *   "update_contravariant_transformation"));
9689 *   Assert(data.update_each & update_volume_elements,
9691 *   "update_volume_elements"));
9692 *  
9693 *   for (unsigned int q = 0; q < output.size(); ++q)
9694 *   for (unsigned int i = 0; i < spacedim; ++i)
9695 *   for (unsigned int j = 0; j < spacedim; ++j)
9696 *   for (unsigned int k = 0; k < spacedim; ++k)
9697 *   {
9698 *   output[q][i][j][k] =
9699 *   input[q][i][j][k] *
9700 *   (data.cell_extents[i] / data.volume_element *
9701 *   data.inverse_cell_extents[j]) *
9702 *   data.inverse_cell_extents[k];
9703 *   }
9704 *  
9705 *   return;
9706 *   }
9707 *  
9708 *   default:
9710 *   }
9711 *   }
9712 *  
9713 *  
9714 *  
9715 *   template <int dim, int spacedim>
9717 *   MappingBox<dim, spacedim>::transform_unit_to_real_cell(
9718 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9719 *   const Point<dim> &p) const
9720 *   {
9721 *   Assert(has_box(cell, polytope_translator), ExcCellNotAssociatedWithBox());
9722 *   Assert(dim == spacedim, ExcNotImplemented());
9723 *  
9724 *   return boxes[polytope_translator.at(cell->active_cell_index())].unit_to_real(
9725 *   p);
9726 *   }
9727 *  
9728 *  
9729 *  
9730 *   template <int dim, int spacedim>
9731 *   Point<dim>
9732 *   MappingBox<dim, spacedim>::transform_real_to_unit_cell(
9733 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9734 *   const Point<spacedim> &p) const
9735 *   {
9736 *   Assert(has_box(cell, polytope_translator), ExcCellNotAssociatedWithBox());
9737 *   Assert(dim == spacedim, ExcNotImplemented());
9738 *  
9739 *   return boxes[polytope_translator.at(cell->active_cell_index())].real_to_unit(
9740 *   p);
9741 *   }
9742 *  
9743 *  
9744 *  
9745 *   template <int dim, int spacedim>
9746 *   void
9747 *   MappingBox<dim, spacedim>::transform_points_real_to_unit_cell(
9748 *   const typename Triangulation<dim, spacedim>::cell_iterator &cell,
9749 *   const ArrayView<const Point<spacedim>> &real_points,
9750 *   const ArrayView<Point<dim>> &unit_points) const
9751 *   {
9752 *   Assert(has_box(cell, polytope_translator), ExcCellNotAssociatedWithBox());
9753 *   AssertDimension(real_points.size(), unit_points.size());
9754 *  
9755 *   if (dim != spacedim)
9757 *   for (unsigned int i = 0; i < real_points.size(); ++i)
9758 *   unit_points[i] =
9759 *   boxes[polytope_translator.at(cell->active_cell_index())].real_to_unit(
9760 *   real_points[i]);
9761 *   }
9762 *  
9763 *  
9764 *  
9765 *   template <int dim, int spacedim>
9766 *   std::unique_ptr<Mapping<dim, spacedim>>
9767 *   MappingBox<dim, spacedim>::clone() const
9768 *   {
9769 *   return std::make_unique<MappingBox<dim, spacedim>>(*this);
9770 *   }
9771 *  
9772 *  
9773 * @endcode
9774 *
9775 * ---------------------------------------------------------------------------
9776 * explicit instantiations
9777 *
9778 * @code
9779 *   template class MappingBox<1>;
9780 *   template class MappingBox<2>;
9781 *   template class MappingBox<3>;
9782 *  
9783 *  
9785 * @endcode
9786
9787
9788*/
*  iterator end()
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  int main(int argc, char **argv)
*  *  iterator begin()
*  x_component_mask set(0, true)
*  *  reference operator*() const
*  *  *  struct InterferenceTaperTransform *  
std::ptrdiff_t difference_type
*  *  Point< dim > operator()(const Point< dim > &p) const * 
*  *  iterator & operator++()
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
bool operator!=(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
void attach_triangulation(const Triangulation< dim, spacedim > &)
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
virtual Tensor< 1, dim, RangeNumberType > gradient(const Point< dim > &p, const unsigned int component=0) const
virtual void value_list(const std::vector< Point< dim > > &points, std::vector< RangeNumberType > &values, const unsigned int component=0) const
virtual RangeNumberType value(const Point< dim > &p, const unsigned int component=0) const
void attach_triangulation(Triangulation< dim, spacedim > &tria)
Definition grid_in.cc:155
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
void initialize(const SparsityPattern &sparsity_pattern)
unsigned int size() const
Definition collection.h:314
#define DEAL_II_VERSION_GTE(major, minor, subminor)
Definition config.h:427
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
unsigned int level
Definition grid_out.cc:4642
unsigned int cell_index
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define DeclExceptionMsg(Exception, defaulttext)
#define AssertThrow(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
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_jacobian_pushed_forward_2nd_derivatives
@ update_volume_elements
Determinant of the Jacobian.
@ update_contravariant_transformation
Contravariant transformation.
@ update_jacobian_pushed_forward_grads
@ update_jacobian_3rd_derivatives
@ update_values
Shape function values.
@ update_jacobian_grads
Gradient of volume element.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_covariant_transformation
Covariant transformation.
@ update_jacobians
Volume element.
@ update_inverse_jacobians
Volume element.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
@ update_default
No update.
@ update_jacobian_pushed_forward_3rd_derivatives
@ update_boundary_forms
Outer normal vector, not normalized.
@ update_jacobian_2nd_derivatives
MappingKind
Definition mapping.h:79
@ mapping_piola
Definition mapping.h:114
@ mapping_covariant_gradient
Definition mapping.h:100
@ mapping_covariant
Definition mapping.h:89
@ mapping_contravariant
Definition mapping.h:94
@ mapping_contravariant_hessian
Definition mapping.h:156
@ mapping_covariant_hessian
Definition mapping.h:150
@ mapping_contravariant_gradient
Definition mapping.h:106
@ mapping_piola_gradient
Definition mapping.h:120
@ mapping_piola_hessian
Definition mapping.h:162
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
void reference_cell(Triangulation< dim, spacedim > &tria, const ReferenceCell< dim > &reference_cell)
void simplex(Triangulation< dim, dim > &tria, const std::vector< Point< dim > > &vertices)
void partition_triangulation(const unsigned int n_partitions, Triangulation< dim, spacedim > &triangulation, const SparsityTools::Partitioner partitioner=SparsityTools::Partitioner::metis)
double volume(const Triangulation< dim, spacedim > &tria)
double diameter(const Triangulation< dim, spacedim > &tria)
@ valid
Iterator points to a valid object.
@ matrix
Contents is actually a matrix.
@ symmetric
Matrix is symmetric.
constexpr types::blas_int one
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Definition advection.h:72
void L2(Vector< number > &result, const FEValuesBase< dim > &fe, const std::vector< double > &input, const double factor=1.)
Definition l2.h:157
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:210
void quadrature_points(const Triangulation< dim, spacedim > &triangulation, const Quadrature< dim > &quadrature, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bounding_boxes, ParticleHandler< dim, spacedim > &particle_handler, const Mapping< dim, spacedim > &mapping=(ReferenceCells::get_hypercube< dim >() .template get_default_linear_mapping< spacedim >()), const std::vector< std::vector< double > > &properties={})
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > l(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
*  *  *  ScaleZFunction< dim, Number, components >::ScaleZFunction *  component(component)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
void apply(const Kokkos::TeamPolicy< MemorySpace::Default::kokkos_space::execution_space >::member_type &team_member, const Kokkos::View< Number *, ShapeDataMemorySpace > shape_data, const ViewTypeIn in, ViewTypeOut out)
constexpr ReferenceCell< dim > Invalid
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices, const Partitioner partitioner=Partitioner::metis)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:118
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:473
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
void save(Archive &ar, const ::std_cxx26::inplace_vector< T, N > &vec, const unsigned int)
Definition hp.h:115
bool check(const ConstraintKinds kind_in, const unsigned int dim)
void copy(const T *begin, const T *end, U *dest)
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition loop.h:68
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
constexpr double PI
Definition numbers.h:240
T signaling_nan()
constexpr types::subdomain_id invalid_subdomain_id
Definition types.h:385
STL namespace.
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
Definition types.h:30
unsigned int subdomain_id
Definition types.h:50
unsigned short int fe_index
Definition types.h:70
unsigned int global_cell_index
Definition types.h:136
void swap(ObserverPointer< T, P > &t1, ObserverPointer< T, Q > &t2)
boost::geometry::index::rtree< LeafType, IndexType, IndexableGetter > RTree
Definition rtree.h:159
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
SynchronousIterators< Iterators > & operator--(SynchronousIterators< Iterators > &a)
void prev(std::tuple< I1, I2 > &t)