// ---------------------------------------------------------------------
//
// Copyright (C) 2001 - 2022 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE.md at
// the top level directory of deal.II.
//
// ---------------------------------------------------------------------

for (X : TRIANGULATIONS; deal_II_dimension : DIMENSIONS;
     deal_II_space_dimension : SPACE_DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace GridTools
    \{
      template std::pair<
        dealii::internal::ActiveCellIterator<deal_II_dimension,
                                             deal_II_space_dimension,
                                             X>::type,
        Point<deal_II_dimension>>
      find_active_cell_around_point(
        const Mapping<deal_II_dimension, deal_II_space_dimension> &,
        const X &,
        const Point<deal_II_space_dimension> &,
        const std::vector<std::set<
          typename dealii::internal::ActiveCellIterator<deal_II_dimension,
                                                        deal_II_space_dimension,
                                                        X>::type>> &,
        const std::vector<std::vector<Tensor<1, deal_II_space_dimension>>> &,
        const dealii::internal::ActiveCellIterator<deal_II_dimension,
                                                   deal_II_space_dimension,
                                                   X>::type &,
        const std::vector<bool> &,
        const RTree<std::pair<Point<deal_II_space_dimension>, unsigned int>> &,
        const double,
        const RTree<std::pair<
          BoundingBox<deal_II_space_dimension>,
          typename Triangulation<deal_II_dimension, deal_II_space_dimension>::
            active_cell_iterator>> *);

      template std::vector<BoundingBox<deal_II_space_dimension>>
      compute_mesh_predicate_bounding_box<X>(
        const X &,
        const std::function<bool(
          const dealii::internal::ActiveCellIterator<deal_II_dimension,
                                                     deal_II_space_dimension,
                                                     X>::type &)> &,
        const unsigned int,
        const bool,
        const unsigned int);
    \}

#endif
  }


// now also instantiate a few additional functions for
// parallel::distributed::Triangulation
for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace GridTools
    \{

      template unsigned int
      find_closest_vertex_of_cell<deal_II_dimension, deal_II_space_dimension>(
        const typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator &,
        const Point<deal_II_space_dimension> &,
        const Mapping<deal_II_dimension, deal_II_space_dimension> &);

      template std::map<unsigned int, types::global_vertex_index>
      compute_local_to_global_vertex_index_map(
        const parallel::distributed::Triangulation<deal_II_dimension,
                                                   deal_II_space_dimension>
          &triangulation);

      template std::map<unsigned int, Point<deal_II_space_dimension>>
      extract_used_vertices(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &mesh,
        const Mapping<deal_II_dimension, deal_II_space_dimension> &mapping);

      template std::pair<
        typename Triangulation<deal_II_dimension,
                               deal_II_space_dimension>::active_cell_iterator,
        Point<deal_II_dimension>>
      find_active_cell_around_point(
        const Cache<deal_II_dimension, deal_II_space_dimension> &,
        const Point<deal_II_space_dimension> &,
        const typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator &,
        const std::vector<bool> &,
        const double);

      template std::tuple<std::vector<typename Triangulation<
                            deal_II_dimension,
                            deal_II_space_dimension>::active_cell_iterator>,
                          std::vector<std::vector<Point<deal_II_dimension>>>,
                          std::vector<std::vector<unsigned int>>,
                          std::vector<unsigned int>>
      compute_point_locations_try_all(
        const Cache<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<Point<deal_II_space_dimension>> &,
        const typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator &);

      template std::tuple<std::vector<typename Triangulation<
                            deal_II_dimension,
                            deal_II_space_dimension>::active_cell_iterator>,
                          std::vector<std::vector<Point<deal_II_dimension>>>,
                          std::vector<std::vector<unsigned int>>>
      compute_point_locations(
        const Cache<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<Point<deal_II_space_dimension>> &,
        const typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator &);

      template std::tuple<
        std::vector<typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator>,
        std::vector<std::vector<Point<deal_II_dimension>>>,
        std::vector<std::vector<unsigned int>>,
        std::vector<std::vector<Point<deal_II_space_dimension>>>,
        std::vector<std::vector<unsigned int>>>
      distributed_compute_point_locations(
        const Cache<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<Point<deal_II_space_dimension>> &,
        const std::vector<std::vector<BoundingBox<deal_II_space_dimension>>> &,
        const double tolerance);

      template internal::DistributedComputePointLocationsInternal<
        deal_II_dimension,
        deal_II_space_dimension>
      internal::distributed_compute_point_locations(
        const Cache<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<Point<deal_II_space_dimension>> &,
        const std::vector<std::vector<BoundingBox<deal_II_space_dimension>>> &,
        const std::vector<bool> &marked_vertices,
        const double,
        const bool,
        const bool);
    \}

#endif
  }



for (deal_II_space_dimension : SPACE_DIMENSIONS)
  {
    dealii::internal::ActiveCellIterator<
      deal_II_space_dimension,
      deal_II_space_dimension,
      parallel::distributed::Triangulation<deal_II_space_dimension,
                                           deal_II_space_dimension>>::type
    find_active_cell_around_point(
      const parallel::distributed::Triangulation<deal_II_space_dimension> &,
      const Point<deal_II_space_dimension> &p);

    template unsigned int GridTools::find_closest_vertex(
      const std::map<unsigned int, Point<deal_II_space_dimension>> &vertices,
      const Point<deal_II_space_dimension> &                        p);

    template std::vector<std::vector<BoundingBox<deal_II_space_dimension>>>
    GridTools::exchange_local_bounding_boxes(
      const std::vector<BoundingBox<deal_II_space_dimension>> &,
      const MPI_Comm &);

    template std::tuple<std::vector<std::vector<unsigned int>>,
                        std::map<unsigned int, unsigned int>,
                        std::map<unsigned int, std::vector<unsigned int>>>
    GridTools::guess_point_owner(
      const std::vector<std::vector<BoundingBox<deal_II_space_dimension>>> &,
      const std::vector<Point<deal_II_space_dimension>> &);

    template std::tuple<std::map<unsigned int, std::vector<unsigned int>>,
                        std::map<unsigned int, unsigned int>,
                        std::map<unsigned int, std::vector<unsigned int>>>
    GridTools::guess_point_owner(
      const RTree<std::pair<BoundingBox<deal_II_space_dimension>, unsigned int>>
        &,
      const std::vector<Point<deal_II_space_dimension>> &);

    template RTree<
      std::pair<BoundingBox<deal_II_space_dimension>, unsigned int>>
    GridTools::build_global_description_tree(
      const std::vector<BoundingBox<deal_II_space_dimension>> &,
      const MPI_Comm &);

    template Vector<double> GridTools::compute_aspect_ratio_of_cells(
      const Mapping<deal_II_space_dimension> &,
      const Triangulation<deal_II_space_dimension> &,
      const Quadrature<deal_II_space_dimension> &);

    template double GridTools::compute_maximum_aspect_ratio(
      const Mapping<deal_II_space_dimension> &,
      const Triangulation<deal_II_space_dimension> &,
      const Quadrature<deal_II_space_dimension> &);
  }


for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace GridTools
    \{
      template double
      diameter(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template double
      volume(const Triangulation<deal_II_dimension, deal_II_space_dimension> &,
             const Mapping<deal_II_dimension, deal_II_space_dimension> &);

      template std::pair<
        DerivativeForm<1, deal_II_dimension, deal_II_space_dimension>,
        Tensor<1, deal_II_space_dimension>>
      affine_cell_approximation<deal_II_dimension, deal_II_space_dimension>(
        const ArrayView<const Point<deal_II_space_dimension>> &);

      template BoundingBox<deal_II_space_dimension>
      compute_bounding_box(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template std::tuple<std::vector<Point<deal_II_space_dimension>>,
                          std::vector<CellData<deal_II_dimension>>,
                          SubCellData>
      get_coarse_mesh_description(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &tria);

      template void
      delete_unused_vertices(std::vector<Point<deal_II_space_dimension>> &,
                             std::vector<CellData<deal_II_dimension>> &,
                             SubCellData &);

      template void
      delete_duplicated_vertices(std::vector<Point<deal_II_space_dimension>> &,
                                 std::vector<CellData<deal_II_dimension>> &,
                                 SubCellData &,
                                 std::vector<unsigned int> &,
                                 double);

      template void
      invert_all_negative_measure_cells(
        const std::vector<Point<deal_II_space_dimension>> &,
        std::vector<CellData<deal_II_dimension>> &);

      template std::size_t
      invert_cells_with_negative_measure(
        const std::vector<Point<deal_II_space_dimension>> &,
        std::vector<CellData<deal_II_dimension>> &);

#  if deal_II_dimension == deal_II_space_dimension
      template void
      consistently_order_cells(std::vector<CellData<deal_II_dimension>> &);
#  endif

      template void
      shift<deal_II_dimension>(
        const Tensor<1, deal_II_space_dimension> &,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template void
      scale<deal_II_dimension>(
        const double,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &);

#  if deal_II_space_dimension == 3
      template void
      rotate<deal_II_dimension>(
        const Tensor<1, deal_II_space_dimension, double> &,
        const double,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template void
      rotate<deal_II_dimension>(
        const double,
        const unsigned int,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &);
#  endif

      template void
      distort_random<deal_II_dimension>(
        const double,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const bool,
        const unsigned int);

      template void
      get_face_connectivity_of_cells(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &                     triangulation,
        DynamicSparsityPattern &cell_connectivity);

      template void
      get_vertex_connectivity_of_cells(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &                     triangulation,
        DynamicSparsityPattern &cell_connectivity);

      template void
      get_vertex_connectivity_of_cells_on_level(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &                     triangulation,
        const unsigned int      level,
        DynamicSparsityPattern &cell_connectivity);

      template void
      partition_triangulation(
        const unsigned int,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const SparsityTools::Partitioner);

      template void
      partition_triangulation(
        const unsigned int,
        const std::vector<unsigned int> &,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const SparsityTools::Partitioner);

      template void
      partition_triangulation(
        const unsigned int,
        const SparsityPattern &,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const SparsityTools::Partitioner);

      template void
      partition_triangulation(
        const unsigned int,
        const std::vector<unsigned int> &,
        const SparsityPattern &,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const SparsityTools::Partitioner);

      template void
      partition_triangulation_zorder(
        const unsigned int,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const bool);

      template void
      partition_multigrid_levels(
        Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template std::vector<types::subdomain_id>
      get_subdomain_association(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<CellId> &);

      template void
      get_subdomain_association(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        std::vector<types::subdomain_id> &);

      template unsigned int
      count_cells_with_subdomain_association(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const types::subdomain_id);

      template std::vector<bool>
      get_locally_owned_vertices(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &);

      template double
      minimal_cell_diameter(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &triangulation,
        const Mapping<deal_II_dimension, deal_II_space_dimension> &);

      template double
      maximal_cell_diameter(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &triangulation,
        const Mapping<deal_II_dimension, deal_II_space_dimension> &);

      template std::map<unsigned int, Point<deal_II_space_dimension>>
      get_all_vertices_at_boundary(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &tria);

      template std::vector<
        std::set<Triangulation<deal_II_dimension,
                               deal_II_space_dimension>::active_cell_iterator>>
      vertex_to_cell_map(
        const Triangulation<deal_II_dimension, deal_II_space_dimension>
          &triangulation);

      template std::vector<std::vector<Tensor<1, deal_II_space_dimension>>>
      vertex_to_cell_centers_directions(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &mesh,
        const std::vector<std::set<typename Triangulation<
          deal_II_dimension,
          deal_II_space_dimension>::active_cell_iterator>> &vertex_to_cells);

#  if deal_II_dimension == deal_II_space_dimension
#    if deal_II_dimension > 1
      template void
      laplace_transform(
        const std::map<unsigned int, Point<deal_II_dimension>> &new_points,
        Triangulation<deal_II_dimension> &                      triangulation,
        const Function<deal_II_dimension> *                     coefficient,
        const bool);

      template Triangulation<deal_II_dimension,
                             deal_II_space_dimension>::DistortedCellList
      fix_up_distorted_child_cells(
        const Triangulation<deal_II_dimension,
                            deal_II_space_dimension>::DistortedCellList
          &distorted_cells,
        Triangulation<deal_II_dimension, deal_II_space_dimension>
          &triangulation);
#    endif
#  endif
    \}
#endif
  }

for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
  {
#if deal_II_space_dimension >= deal_II_dimension
    namespace GridTools
    \{
      template void
      copy_boundary_to_manifold_id<deal_II_dimension, deal_II_space_dimension>(
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const bool);

      template void
      copy_material_to_manifold_id<deal_II_dimension, deal_II_space_dimension>(
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const bool);

      template void
      map_boundary_to_manifold_ids<deal_II_dimension, deal_II_space_dimension>(
        const std::vector<types::boundary_id> &,
        const std::vector<types::manifold_id> &,
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<types::boundary_id> &);

      template void
      assign_co_dimensional_manifold_indicators(
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        const std::function<
          types::manifold_id(const std::set<types::manifold_id> &)> &,
        bool);

      template void
      regularize_corner_cells(
        Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        double);

      template void
      collect_coinciding_vertices(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &,
        std::map<unsigned int, std::vector<unsigned int>> &,
        std::map<unsigned int, unsigned int> &);

      template std::map<unsigned int, std::set<dealii::types::subdomain_id>>
      compute_vertices_with_ghost_neighbors(
        const Triangulation<deal_II_dimension, deal_II_space_dimension> &);
    \}
#endif
  }


for (deal_II_dimension : DIMENSIONS)
  {
    template std::pair<unsigned int, double>
      GridTools::get_longest_direction<deal_II_dimension, deal_II_dimension>(
        Triangulation<deal_II_dimension>::active_cell_iterator);

    template void
    GridTools::remove_hanging_nodes<deal_II_dimension, deal_II_dimension>(
      Triangulation<deal_II_dimension> & tria, bool, unsigned int);

    template void
    GridTools::remove_anisotropy<deal_II_dimension, deal_II_dimension>(
      Triangulation<deal_II_dimension> &, double, unsigned int);

#if deal_II_dimension < 3
    template std::pair<unsigned int, double>
      GridTools::get_longest_direction<deal_II_dimension,
                                       deal_II_dimension + 1>(
        Triangulation<deal_II_dimension,
                      deal_II_dimension + 1>::active_cell_iterator);

    template void
    GridTools::remove_hanging_nodes<deal_II_dimension, deal_II_dimension + 1>(
      Triangulation<deal_II_dimension, deal_II_dimension + 1> & tria,
      bool,
      unsigned int);

    template void
    GridTools::remove_anisotropy<deal_II_dimension, deal_II_dimension + 1>(
      Triangulation<deal_II_dimension, deal_II_dimension + 1> &,
      double,
      unsigned int);
#endif
  }

for (deal_II_vec : REAL_NONBLOCK_VECTORS; deal_II_dimension : DIMENSIONS)
  {
#if deal_II_dimension > 1
    template class GridTools::MarchingCubeAlgorithm<deal_II_dimension,
                                                    deal_II_vec>;
#endif
  }
