// ---------------------------------------------------------------------
//
// Copyright (C) 2009 - 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 (deal_II_dimension, deal_II_space_dimension : DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace DoFTools
    \{
      template IndexSet
      extract_locally_relevant_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &dof_handler);

      template void
      extract_locally_relevant_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &       dof_handler,
        IndexSet &dof_set);

      template IndexSet
      extract_locally_relevant_level_dofs<deal_II_dimension,
                                          deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &                dof_handler,
        const unsigned int level);

      template void
      extract_locally_relevant_level_dofs<deal_II_dimension,
                                          deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &                dof_handler,
        const unsigned int level,
        IndexSet &         dof_set);

      template IndexSet
      extract_locally_active_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &dof_handler);

      template void
      extract_locally_active_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &       dof_handler,
        IndexSet &dof_set);

      template IndexSet
      extract_locally_active_level_dofs<deal_II_dimension,
                                        deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &                dof_handler,
        const unsigned int level);

      template void
      extract_locally_active_level_dofs<deal_II_dimension,
                                        deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &                dof_handler,
        IndexSet &         dof_set,
        const unsigned int level);

      template std::vector<IndexSet>
      locally_owned_dofs_per_component<deal_II_dimension,
                                       deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension>
          &                  dof_handler,
        const ComponentMask &components);

      template std::vector<types::global_dof_index>
      count_dofs_per_fe_component<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const bool,
        const std::vector<unsigned int> &);

      template std::vector<types::global_dof_index>
      count_dofs_per_fe_block<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const std::vector<unsigned int> &);


      template unsigned int
      count_dofs_on_patch<deal_II_dimension, deal_II_space_dimension>(
        const std::vector<
          DoFHandler<deal_II_dimension,
                     deal_II_space_dimension>::active_cell_iterator> &patch);

      template std::vector<types::global_dof_index>
      get_dofs_on_patch<deal_II_dimension, deal_II_space_dimension>(
        const std::vector<
          DoFHandler<deal_II_dimension,
                     deal_II_space_dimension>::active_cell_iterator> &patch);

      template IndexSet
      extract_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const ComponentMask &);

      template IndexSet
      extract_dofs<deal_II_dimension, deal_II_space_dimension>(
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const BlockMask &);
    \}
#endif
  }



for (deal_II_dimension : DIMENSIONS)
  {
    template std::vector<unsigned int> DoFTools::make_vertex_patches(
      SparsityPattern &,
      const DoFHandler<deal_II_dimension> &,
      unsigned int,
      bool,
      bool,
      bool,
      bool,
      bool);

    template std::vector<unsigned int> DoFTools::make_vertex_patches(
      SparsityPattern &,
      const DoFHandler<deal_II_dimension> &,
      unsigned int,
      const BlockMask &,
      bool,
      bool,
      bool,
      bool);

    template void DoFTools::make_single_patch(
      SparsityPattern &,
      const DoFHandler<deal_II_dimension> &,
      unsigned int,
      bool);

    template void DoFTools::make_child_patches(
      SparsityPattern &,
      const DoFHandler<deal_II_dimension> &,
      unsigned int,
      bool,
      bool);

    // TODO: can cleanup a bit more to fit into the scheme used above

    template void DoFTools::distribute_cell_to_dof_vector<deal_II_dimension,
                                                          deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      const Vector<float> &                cell_data,
      Vector<double> &                     dof_data,
      const unsigned int                   component);
    template void DoFTools::distribute_cell_to_dof_vector<deal_II_dimension,
                                                          deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      const Vector<double> &               cell_data,
      Vector<double> &                     dof_data,
      const unsigned int                   component);

    template void
    DoFTools::extract_boundary_dofs<deal_II_dimension, deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &,
      const ComponentMask &,
      std::vector<bool> &,
      const std::set<types::boundary_id> &);

    template void
    DoFTools::extract_boundary_dofs<deal_II_dimension, deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &,
      const ComponentMask &,
      IndexSet &,
      const std::set<types::boundary_id> &);

    template IndexSet
    DoFTools::extract_boundary_dofs<deal_II_dimension, deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &,
      const ComponentMask &,
      const std::set<types::boundary_id> &);

    template void DoFTools::extract_dofs_with_support_on_boundary<
      deal_II_dimension,
      deal_II_dimension>(const DoFHandler<deal_II_dimension> &,
                         const ComponentMask &,
                         std::vector<bool> &,
                         const std::set<types::boundary_id> &);

    template IndexSet DoFTools::extract_hanging_node_dofs(
      const DoFHandler<deal_II_dimension> &);

    template void DoFTools::extract_subdomain_dofs<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      const types::subdomain_id            subdomain_id,
      std::vector<bool> &                  selected_dofs);

    template void DoFTools::extract_constant_modes<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      const ComponentMask &                selected_components,
      std::vector<std::vector<bool>> &     constant_modes);

    template void DoFTools::get_active_fe_indices<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      std::vector<unsigned int> &          active_fe_indices);

    template void DoFTools::get_subdomain_association<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler,
      std::vector<types::subdomain_id> &   subdomain_association);

    template std::vector<IndexSet>
    DoFTools::locally_owned_dofs_per_subdomain<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler);

    template std::vector<IndexSet>
    DoFTools::locally_relevant_dofs_per_subdomain<deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &dof_handler);

    template unsigned int
    DoFTools::count_dofs_with_subdomain_association<deal_II_dimension,
                                                    deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &, const types::subdomain_id);
    template IndexSet
    DoFTools::dof_indices_with_subdomain_association<deal_II_dimension,
                                                     deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &, const types::subdomain_id);
    template void DoFTools::count_dofs_with_subdomain_association<
      deal_II_dimension,
      deal_II_dimension>(const DoFHandler<deal_II_dimension> &,
                         const types::subdomain_id,
                         std::vector<unsigned int> &);

#if deal_II_dimension < 3

    template void
    DoFTools::extract_boundary_dofs<deal_II_dimension, deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const ComponentMask &,
      std::vector<bool> &,
      const std::set<types::boundary_id> &);

    template void
    DoFTools::extract_boundary_dofs<deal_II_dimension, deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const ComponentMask &,
      IndexSet &,
      const std::set<types::boundary_id> &);

    template unsigned int
    DoFTools::count_dofs_with_subdomain_association<deal_II_dimension,
                                                    deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const types::subdomain_id);

    template IndexSet
    DoFTools::dof_indices_with_subdomain_association<deal_II_dimension,
                                                     deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const types::subdomain_id);
    template void
    DoFTools::count_dofs_with_subdomain_association<deal_II_dimension,
                                                    deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const types::subdomain_id,
      std::vector<unsigned int> &);

    template void DoFTools::get_subdomain_association<deal_II_dimension,
                                                      deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &dof_handler,
      std::vector<types::subdomain_id> &subdomain_association);

    template std::vector<IndexSet>
    DoFTools::locally_owned_dofs_per_subdomain<deal_II_dimension,
                                               deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &dof_handler);

    template std::vector<IndexSet>
    DoFTools::locally_relevant_dofs_per_subdomain<deal_II_dimension,
                                                  deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &dof_handler);

#endif

#if deal_II_dimension == 3
    template void DoFTools::extract_boundary_dofs<1, 3>(
      const DoFHandler<1, 3> &,
      const ComponentMask &,
      std::vector<bool> &,
      const std::set<types::boundary_id> &);

    template void DoFTools::extract_boundary_dofs<1, 3>(
      const DoFHandler<1, 3> &,
      const ComponentMask &,
      IndexSet &,
      const std::set<types::boundary_id> &);

    template void DoFTools::get_subdomain_association<1, 3>(
      const DoFHandler<1, 3> &          dof_handler,
      std::vector<types::subdomain_id> &subdomain_association);

    template std::vector<IndexSet>
    DoFTools::locally_owned_dofs_per_subdomain<1, 3>(
      const DoFHandler<1, 3> &dof_handler);

    template std::vector<IndexSet>
    DoFTools::locally_relevant_dofs_per_subdomain<1, 3>(
      const DoFHandler<1, 3> &dof_handler);

    template unsigned int DoFTools::count_dofs_with_subdomain_association<1, 3>(
      const DoFHandler<1, 3> &, const types::subdomain_id);
    template IndexSet DoFTools::dof_indices_with_subdomain_association<1, 3>(
      const DoFHandler<1, 3> &, const types::subdomain_id);
    template void DoFTools::count_dofs_with_subdomain_association<1, 3>(
      const DoFHandler<1, 3> &,
      const types::subdomain_id,
      std::vector<unsigned int> &);
#endif

    template void
    DoFTools::map_dof_to_boundary_indices<deal_II_dimension, deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &,
      const std::set<types::boundary_id> &,
      std::vector<types::global_dof_index> &);

    template void
    DoFTools::map_dof_to_boundary_indices<deal_II_dimension, deal_II_dimension>(
      const DoFHandler<deal_II_dimension> &,
      std::vector<types::global_dof_index> &);


#if deal_II_dimension < 3

    template void DoFTools::map_dof_to_boundary_indices<deal_II_dimension,
                                                        deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      const std::set<types::boundary_id> &,
      std::vector<types::global_dof_index> &);

    template void DoFTools::map_dof_to_boundary_indices<deal_II_dimension,
                                                        deal_II_dimension + 1>(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &,
      std::vector<types::global_dof_index> &);

    template IndexSet DoFTools::extract_hanging_node_dofs(
      const DoFHandler<deal_II_dimension, deal_II_dimension + 1> &);

#endif

#if deal_II_dimension == 3

    template void DoFTools::map_dof_to_boundary_indices<1, 3>(
      const DoFHandler<1, 3> &,
      const std::set<types::boundary_id> &,
      std::vector<types::global_dof_index> &);

    template void DoFTools::map_dof_to_boundary_indices<1, 3>(
      const DoFHandler<1, 3> &, std::vector<types::global_dof_index> &);

    template IndexSet DoFTools::extract_hanging_node_dofs(
      const DoFHandler<1, 3> &);

#endif
  }


for (deal_II_dimension : DIMENSIONS)
  {
    template void DoFTools::convert_couplings_to_blocks(
      const DoFHandler<deal_II_dimension> &,
      const Table<2, Coupling> &,
      std::vector<Table<2, Coupling>> &);

    template void DoFTools::write_gnuplot_dof_support_point_info(
      std::ostream &,
      const std::map<types::global_dof_index, Point<deal_II_dimension>> &);
  }


for (deal_II_dimension : DIMENSIONS; S : REAL_AND_COMPLEX_SCALARS)
  {
    template IndexSet
    DoFTools::extract_dofs_with_support_contained_within<deal_II_dimension,
                                                         deal_II_dimension,
                                                         S>(
      const DoFHandler<deal_II_dimension> &,
      const std::function<bool(
        const typename DoFHandler<deal_II_dimension>::active_cell_iterator &)>
        &,
      const AffineConstraints<S> &);
  }


for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace DoFTools
    \{
      template void
      map_dofs_to_support_points<deal_II_dimension, deal_II_space_dimension>(
        const Mapping<deal_II_dimension, deal_II_space_dimension> &,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        std::vector<Point<deal_II_space_dimension>> &,
        const ComponentMask &);

      template void
      map_dofs_to_support_points<deal_II_dimension, deal_II_space_dimension>(
        const hp::MappingCollection<deal_II_dimension, deal_II_space_dimension>
          &,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        std::vector<Point<deal_II_space_dimension>> &,
        const ComponentMask &);

      template void
      map_dofs_to_support_points<deal_II_dimension, deal_II_space_dimension>(
        const Mapping<deal_II_dimension, deal_II_space_dimension> &,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        std::map<types::global_dof_index, Point<deal_II_space_dimension>> &,
        const ComponentMask &);

      template void
      map_dofs_to_support_points<deal_II_dimension, deal_II_space_dimension>(
        const hp::MappingCollection<deal_II_dimension, deal_II_space_dimension>
          &,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        std::map<types::global_dof_index, Point<deal_II_space_dimension>> &,
        const ComponentMask &);
    \}
#endif
  }


for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace DoFTools
    \{
      // extract_level_dofs() for ComponentMask and BlockMask
      template void
      extract_level_dofs<deal_II_dimension, deal_II_space_dimension>(
        const unsigned int level,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const ComponentMask &,
        std::vector<bool> &);

      template void
      extract_level_dofs<deal_II_dimension, deal_II_space_dimension>(
        const unsigned int level,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const BlockMask &,
        std::vector<bool> &);
    \}
#endif
  }


for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : DIMENSIONS)
  {
#if deal_II_dimension <= deal_II_space_dimension
    namespace DoFTools
    \{
      template void
      make_cell_patches<deal_II_dimension, deal_II_space_dimension>(
        SparsityPattern &,
        const DoFHandler<deal_II_dimension, deal_II_space_dimension> &,
        const unsigned int,
        const std::vector<bool> &,
        const types::global_dof_index);

    \}
#endif
  }
