// ---------------------------------------------------------------------
//
// Copyright (C) 2001 - 2016 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 at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------



for (X : TRIANGULATION_AND_DOFHANDLERS; 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 (const X &,
                         const Point<deal_II_space_dimension> &);

  template
    std::vector<dealii::internal::ActiveCellIterator<deal_II_dimension, deal_II_space_dimension, X>::type>
    find_cells_adjacent_to_vertex(const X &, const unsigned int);

  template
    dealii::internal::ActiveCellIterator<deal_II_dimension, deal_II_space_dimension, X>::type
    find_active_cell_around_point (const X &, const Point<deal_II_space_dimension> &p);

  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> &);

  template
    std::vector<dealii::internal::ActiveCellIterator<deal_II_dimension, deal_II_space_dimension, X>::type>
    compute_active_cell_halo_layer (const X &,
                                    const std_cxx11::function<bool (const dealii::internal::ActiveCellIterator<deal_II_dimension, deal_II_space_dimension, X>::type&)> &);

  template
    std::vector<dealii::internal::ActiveCellIterator<deal_II_dimension, deal_II_space_dimension, X>::type>
    compute_ghost_cell_halo_layer (const X &);

  template
    std::list<std::pair<X::cell_iterator, X::cell_iterator> >
    get_finest_common_cells (const X &mesh_1,
                             const X &mesh_2);


  template
    bool
    have_same_coarse_mesh (const X &mesh_1,
                           const X &mesh_2);

  \}

  #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
  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);
  \}

  #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);


    std::pair<dealii::internal::ActiveCellIterator<deal_II_space_dimension, deal_II_space_dimension, parallel::distributed::Triangulation<deal_II_space_dimension, deal_II_space_dimension> >::type, Point<deal_II_space_dimension> >
    find_active_cell_around_point (const Mapping<deal_II_space_dimension> &,
                                   const parallel::distributed::Triangulation<deal_II_space_dimension> &,
                                   const Point<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
      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 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> &);

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

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

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

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

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

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

    template
      std::pair<hp::DoFHandler<deal_II_dimension, deal_II_space_dimension>::active_cell_iterator,
                Point<deal_II_dimension> >
      find_active_cell_around_point
      (const hp::MappingCollection<deal_II_dimension, deal_II_space_dimension> &,
       const hp::DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
       const Point<deal_II_space_dimension> &);

    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);

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

    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);

#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);

#  endif

    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



  }

for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension :  SPACE_DIMENSIONS; Container : DOFHANDLER_TEMPLATES)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace GridTools \{

      template
      std::map< types::global_dof_index,std::vector<Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator> >
      get_dof_to_support_patch_map<Container<deal_II_dimension,deal_II_space_dimension> >
      (Container<deal_II_dimension,deal_II_space_dimension> &dof_handler);
      
      
    \}
#endif
  }


for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension :  SPACE_DIMENSIONS; Container : TRIANGULATION_AND_DOFHANDLER_TEMPLATES)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace GridTools \{

      template
      std::vector<Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator>
      get_patch_around_cell<Container<deal_II_dimension,deal_II_space_dimension> >
      (const Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator &cell);
      
      template
      std::vector< Container<deal_II_dimension,deal_II_space_dimension>::cell_iterator> 
      get_cells_at_coarsest_common_level <Container<deal_II_dimension,deal_II_space_dimension> > (
      const std::vector< Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator> & patch_cells);
      
      template
      void build_triangulation_from_patch <Container<deal_II_dimension,deal_II_space_dimension> > (
      const std::vector<Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator>  &patch,
      Triangulation<Container<deal_II_dimension,deal_II_space_dimension>::dimension,Container<deal_II_dimension,deal_II_space_dimension>::space_dimension> &local_triangulation,
      std::map<Triangulation<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator,
      Container<deal_II_dimension,deal_II_space_dimension>::active_cell_iterator > &patch_to_global_tria_map);
      
    \}
#endif
  }


// instantiate the following functions only for the "sequential" containers. this
// is a misnomer here, however: the point is simply that we only instantiate
// these functions for certain *iterator* types, and the iterator types are
// the same for sequential and parallel containers; consequently, we get duplicate
// instantiation errors if we instantiate for *all* container types, rather than
// only the sequential ones
for (X : SEQUENTIAL_TRIANGULATION_AND_DOFHANDLERS; deal_II_dimension : DIMENSIONS ; deal_II_space_dimension : SPACE_DIMENSIONS)
{
#if deal_II_dimension <= deal_II_space_dimension
  namespace GridTools \{

    template
    bool orthogonal_equality<X::active_face_iterator> (std::bitset<3> &,
                                                       const X::active_face_iterator&,
                                                       const X::active_face_iterator&,
                                                       const int,
                                                       const Tensor<1,deal_II_space_dimension> &,
                                                       const FullMatrix<double> &);

    template
    bool orthogonal_equality<X::face_iterator> (std::bitset<3> &,
                                                const X::face_iterator&,
                                                const X::face_iterator&,
                                                const int,
                                                const Tensor<1,deal_II_space_dimension> &,
                                                const FullMatrix<double> &);

    template
    bool orthogonal_equality<X::active_face_iterator> (const X::active_face_iterator&,
                                                       const X::active_face_iterator&,
                                                       const int,
                                                       const Tensor<1,deal_II_space_dimension> &,
                                                       const FullMatrix<double> &);

    template
    bool orthogonal_equality<X::face_iterator> (const X::face_iterator&,
                                                const X::face_iterator&,
                                                const int,
                                                const Tensor<1,deal_II_space_dimension> &,
                                                const FullMatrix<double> &);

    template
    void collect_periodic_faces<X> (const X &,
                                    const types::boundary_id,
                                    const types::boundary_id,
                                    const int,
                                    std::vector<PeriodicFacePair<X::cell_iterator> > &,
                                    const Tensor<1,X::space_dimension> &,
                                    const FullMatrix<double> &);

    template
    void collect_periodic_faces<X> (const X &,
                                    const types::boundary_id,
                                    const int,
                                    std::vector<PeriodicFacePair<X::cell_iterator> > &,
                                    const Tensor<1,X::space_dimension> &,
                                    const FullMatrix<double> &);

  \}
#endif
}

for (deal_II_dimension : DIMENSIONS ; deal_II_space_dimension : SPACE_DIMENSIONS)
{
#if deal_II_dimension <= deal_II_space_dimension
   #if deal_II_dimension >= 2

     namespace GridTools \{
      template
      void
      collect_periodic_faces<parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension> >
                                 (const parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension> &,
                                  const types::boundary_id,
                                  const types::boundary_id,
                                  const int,
                                  std::vector<PeriodicFacePair<parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension>::cell_iterator> > &,
                                  const Tensor<1,parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension>::space_dimension> &,
                                  const FullMatrix<double> &);

      template
      void
      collect_periodic_faces<parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension> >
                                 (const parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension> &,
                                  const types::boundary_id,
                                  const int,
                                  std::vector<PeriodicFacePair<parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension>::cell_iterator> > &,
                                  const Tensor<1,parallel::distributed::Triangulation<deal_II_dimension, deal_II_space_dimension>::space_dimension> &,
                                  const FullMatrix<double> &);
     \}
   #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);

\}
#endif
}
