// ---------------------------------------------------------------------
//
// Copyright (C) 2016 - 2021 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.
//
// ---------------------------------------------------------------------


#ifndef DOXYGEN

for (S : REAL_SCALARS)
  {
    template void sum<S>(const SparseMatrix<S> &,
                         const MPI_Comm &,
                         SparseMatrix<S> &);
  }

for (S : MPI_SCALARS)
  {
    template void sum<LAPACKFullMatrix<S>>(const LAPACKFullMatrix<S> &,
                                           const MPI_Comm &,
                                           LAPACKFullMatrix<S> &);

    template void sum<Vector<S>>(const Vector<S> &,
                                 const MPI_Comm &,
                                 Vector<S> &);

    template void sum<FullMatrix<S>>(const FullMatrix<S> &,
                                     const MPI_Comm &,
                                     FullMatrix<S> &);

    template void sum<S>(const ArrayView<const S> &,
                         const MPI_Comm &,
                         const ArrayView<S> &);

    template S sum<S>(const S &, const MPI_Comm &);

    template void sum<std::vector<S>>(const std::vector<S> &,
                                      const MPI_Comm &,
                                      std::vector<S> &);

    template S max<S>(const S &, const MPI_Comm &);

    template void max<std::vector<S>>(const std::vector<S> &,
                                      const MPI_Comm &,
                                      std::vector<S> &);

    template void max<S>(const ArrayView<const S> &,
                         const MPI_Comm &,
                         const ArrayView<S> &);

    template S min<S>(const S &, const MPI_Comm &);

    template void min<std::vector<S>>(const std::vector<S> &,
                                      const MPI_Comm &,
                                      std::vector<S> &);

    template void min<S>(const ArrayView<const S> &,
                         const MPI_Comm &,
                         const ArrayView<S> &);

    template S reduce(const S &                                     vec,
                      const MPI_Comm &                              comm,
                      const std::function<S(const S &, const S &)> &process,
                      const unsigned int root_process);

    template std::vector<S> reduce(
      const std::vector<S> &                                       vec,
      const MPI_Comm &                                             comm,
      const std::function<std::vector<S>(const std::vector<S> &,
                                         const std::vector<S> &)> &process,
      const unsigned int root_process);

    template S all_reduce(
      const S &                                     vec,
      const MPI_Comm &                              comm,
      const std::function<S(const S &, const S &)> &process);

    template std::vector<S> all_reduce(
      const std::vector<S> &                                       vec,
      const MPI_Comm &                                             comm,
      const std::function<std::vector<S>(const std::vector<S> &,
                                         const std::vector<S> &)> &process);

    // The fixed-length array (i.e., things declared like T(&values)[N])
    // versions of the functions above live in the header file mpi.h since the
    // length (N) is a compile-time constant. Those functions all call
    // Utilities::MPI::internal::all_reduce, which is declared in
    // mpi.templates.h, so that function (all_reduce) must be present in the
    // compiled library.
    //
    // Note for the curious: it turns out that most compilers and most compiler
    // settings will not inline this function, meaning that it consistently
    // shows up in the shared object files without this explicit instantiation
    // in debug mode and usually in release mode. In particular, GCC 6 does not
    // inline it (so this instantiation is not necessary) but clang 3.8 does (so
    // this instantiation is necessary). Some versions of GCC (5.3 but not 4.8)
    // seem to inline it with the '-march=native' flag.
    template void Utilities::MPI::internal::all_reduce<S>(
      const MPI_Op &,
      const ArrayView<const S> &,
      const MPI_Comm &,
      const ArrayView<S> &);
  }


for (S : REAL_SCALARS; rank : RANKS; dim : SPACE_DIMENSIONS)
  {
    template Tensor<rank, dim, S> sum<rank, dim, S>(
      const Tensor<rank, dim, S> &, const MPI_Comm &);
  }


// Recall that SymmetricTensor only makes sense for rank 2 and 4
for (S : REAL_SCALARS; dim : SPACE_DIMENSIONS)
  {
    template SymmetricTensor<2, dim, S> sum<2, dim, S>(
      const SymmetricTensor<2, dim, S> &, const MPI_Comm &);

    template SymmetricTensor<4, dim, S> sum<4, dim, S>(
      const SymmetricTensor<4, dim, S> &, const MPI_Comm &);
  }


#endif
