]> https://gitweb.dealii.org/ - dealii.git/commitdiff
make Utilities::MPI::sum() support SparseMatrix
authorDenis Davydov <davydden@gmail.com>
Fri, 16 Mar 2018 19:06:44 +0000 (20:06 +0100)
committerDenis Davydov <davydden@gmail.com>
Mon, 19 Mar 2018 13:53:53 +0000 (14:53 +0100)
include/deal.II/base/mpi.h
include/deal.II/base/mpi.templates.h
include/deal.II/lac/sparse_matrix.h
source/base/mpi.inst.in
tests/mpi/collective_sparse_matrix_01.cc [new file with mode: 0644]
tests/mpi/collective_sparse_matrix_01.mpirun=1.output [new file with mode: 0644]
tests/mpi/collective_sparse_matrix_01.mpirun=3.output [new file with mode: 0644]

index 2dd20725c30898cace4da45a3f92e0f7e0b3adc3..7084595734cca6795e2fd6333dda497b605cf49e 100644 (file)
@@ -52,7 +52,7 @@ DEAL_II_NAMESPACE_OPEN
 //Forward type declarations to allow MPI sums over tensorial types
 template <int rank, int dim, typename Number> class Tensor;
 template <int rank, int dim, typename Number> class SymmetricTensor;
-
+template <typename Number> class SparseMatrix;
 
 namespace Utilities
 {
@@ -196,6 +196,20 @@ namespace Utilities
     sum (const Tensor<rank,dim,Number> &local,
          const MPI_Comm &mpi_communicator);
 
+    /**
+     * Perform an MPI sum of the entries of a SparseMatrix.
+     *
+     * @note @p local and @p global should have the same sparsity
+     * pattern and it should be the same for all MPI processes.
+     *
+     * @relatesalso SparseMatrix
+     */
+    template <typename Number>
+    void
+    sum (const SparseMatrix<Number> &local,
+         const MPI_Comm &mpi_communicator,
+         SparseMatrix<Number> &global);
+
     /**
      * Return the maximum over all processors of the value @p t. This function
      * is collective over all processors given in the
index 5c8cc75a96625be1a3c93b447799207b8878daa7..8302d7cdc9371ecd3babe867ce3ed47527b094f5 100644 (file)
@@ -24,6 +24,7 @@
 #include <deal.II/lac/vector.h>
 #include <deal.II/lac/full_matrix.h>
 #include <deal.II/lac/lapack_full_matrix.h>
+#include <deal.II/lac/sparse_matrix.h>
 
 #include <vector>
 
@@ -235,7 +236,7 @@ namespace Utilities
          const MPI_Comm &mpi_communicator)
     {
       Tensor<rank, dim, Number> sums;
-      dealii::Utilities::MPI::sum(local, mpi_communicator, sums);
+      sum(local, mpi_communicator, sums);
       return sums;
     }
 
@@ -253,7 +254,7 @@ namespace Utilities
         entries[i] = local[ local.unrolled_to_component_indices(i) ];
 
       Number global_entries[ SymmetricTensor<rank,dim,Number>::n_independent_components ];
-      dealii::Utilities::MPI::sum( entries, mpi_communicator, global_entries );
+      sum( entries, mpi_communicator, global_entries );
 
       SymmetricTensor<rank,dim,Number> global;
       for (unsigned int i=0; i< n_entries; ++i)
@@ -264,6 +265,29 @@ namespace Utilities
 
 
 
+    template <typename Number>
+    void
+    sum (const SparseMatrix<Number> &local,
+         const MPI_Comm &mpi_communicator,
+         SparseMatrix<Number> &global)
+    {
+      Assert(local.get_sparsity_pattern() == global.get_sparsity_pattern(),
+             ExcMessage("The sparsity pattern of the local and the global matrices should match."));
+#ifdef DEAL_II_WITH_MPI
+      // makes use of the fact that the matrix stores its data in a
+      // contiguous array.
+      sum(ArrayView<const Number> (&local.val[0], local.n_nonzero_elements()),
+          mpi_communicator,
+          ArrayView<Number>(&global.val[0], global.n_nonzero_elements()));
+#else
+      (void)mpi_communicator;
+      if (!PointerComparison::equal (&local, &global))
+        global = local;
+#endif
+    }
+
+
+
     template <typename T>
     T max (const T &t,
            const MPI_Comm &mpi_communicator)
index 7c87cd702246de04902deb4fc1cb28220478721a..42edaa941f8ed372c1245f11fb409417b54923ca 100644 (file)
@@ -24,6 +24,9 @@
 #include <deal.II/lac/identity_matrix.h>
 #include <deal.II/lac/exceptions.h>
 #include <deal.II/lac/vector_operation.h>
+#ifdef DEAL_II_WITH_MPI
+#include <mpi.h>
+#endif
 
 #include <memory>
 
@@ -34,6 +37,15 @@ template <typename number> class Vector;
 template <typename number> class FullMatrix;
 template <typename Matrix> class BlockMatrixBase;
 template <typename number> class SparseILU;
+#ifdef DEAL_II_WITH_MPI
+namespace Utilities
+{
+  namespace MPI
+  {
+    template <typename Number> void sum (const SparseMatrix<Number> &, const MPI_Comm &, SparseMatrix<Number> &);
+  }
+}
+#endif
 
 #ifdef DEAL_II_WITH_TRILINOS
 namespace TrilinosWrappers
@@ -974,8 +986,14 @@ public:
    * classes instead, since they are tailored better to a sparse matrix
    * structure.
    */
-  number operator () (const size_type i,
-                      const size_type j) const;
+  const number &operator () (const size_type i,
+                             const size_type j) const;
+
+  /**
+   * In contrast to the one above, this function allows modifying the object.
+   */
+  number &operator () (const size_type i,
+                       const size_type j);
 
   /**
    * This function is mostly like operator()() in that it returns the value of
@@ -1628,6 +1646,13 @@ private:
    */
   template <typename,bool> friend class SparseMatrixIterators::Iterator;
   template <typename,bool> friend class SparseMatrixIterators::Accessor;
+
+#ifdef DEAL_II_WITH_MPI
+  /**
+   * Give access to internal datastructures to perform MPI operations.
+   */
+  template <typename Number> friend void Utilities::MPI::sum (const SparseMatrix<Number> &, const MPI_Comm &, SparseMatrix<Number> &);
+#endif
 };
 
 #ifndef DOXYGEN
@@ -1868,8 +1893,21 @@ SparseMatrix<number>::operator /= (const number factor)
 
 template <typename number>
 inline
-number SparseMatrix<number>::operator () (const size_type i,
-                                          const size_type j) const
+const number &SparseMatrix<number>::operator () (const size_type i,
+                                                 const size_type j) const
+{
+  Assert (cols != nullptr, ExcNotInitialized());
+  Assert (cols->operator()(i,j) != SparsityPattern::invalid_entry,
+          ExcInvalidIndex(i,j));
+  return val[cols->operator()(i,j)];
+}
+
+
+
+template <typename number>
+inline
+number &SparseMatrix<number>::operator () (const size_type i,
+                                           const size_type j)
 {
   Assert (cols != nullptr, ExcNotInitialized());
   Assert (cols->operator()(i,j) != SparsityPattern::invalid_entry,
index a20a7fbcafb37068e0c74d696564b86f48ae0e51..704c9c780d27d6df1aee21c91de2748e00cde7c2 100644 (file)
 // ---------------------------------------------------------------------
 
 
+for (S : REAL_SCALARS)
+{
+    template
+    void sum<S> (const SparseMatrix<S> &, const MPI_Comm &, SparseMatrix<S> &);
+}
+
 for (S : MPI_SCALARS)
 {
     template
diff --git a/tests/mpi/collective_sparse_matrix_01.cc b/tests/mpi/collective_sparse_matrix_01.cc
new file mode 100644 (file)
index 0000000..6845ff9
--- /dev/null
@@ -0,0 +1,95 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2017 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.
+//
+// ---------------------------------------------------------------------
+
+
+// test Utilities::MPI::sum() for sparse matrix
+
+#include "../tests.h"
+#include "../testmatrix.h"
+#include <deal.II/lac/sparse_matrix.h>
+#include <deal.II/base/mpi.h>
+
+
+
+void test()
+{
+  const unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  const unsigned int size = 50;
+
+  FDMatrix testproblem (size, size);
+  unsigned int dim = (size-1) * (size-1);
+
+  SparsityPattern sparsity(dim, dim, size);
+  testproblem.five_point_structure(sparsity);
+  sparsity.compress();
+
+  SparseMatrix<double> matrix(sparsity);
+  const double val = std::pow(10,myid);
+  for (SparsityPattern::const_iterator it = sparsity.begin();
+       it != sparsity.end(); ++it)
+    {
+      const auto i = (*it).row();
+      const auto j = (*it).column();
+      matrix.add(i, j, -val);
+      matrix.add(i, i, val);
+    }
+
+  // compare with FullMatrix:
+  FullMatrix<double> full(dim,dim);
+  full.copy_from(matrix);
+
+  // deallog << "Local:" << std::endl;
+  // matrix.print(deallog.get_file_stream());
+  Utilities::MPI::sum(matrix, MPI_COMM_WORLD, matrix);
+  // deallog << "Global:" << std::endl;
+  // matrix.print(deallog.get_file_stream());
+
+  Utilities::MPI::sum(full, MPI_COMM_WORLD, full);
+
+  for (SparsityPattern::const_iterator it = sparsity.begin();
+       it != sparsity.end(); ++it)
+    {
+      const auto i = (*it).row();
+      const auto j = (*it).column();
+      AssertThrow (matrix(i,j) == full(i,j),
+                   ExcMessage(std::to_string(matrix(i,j)) +
+                              " != " +
+                              std::to_string(full(i,j)) +
+                              " for i=" + std::to_string(i) +
+                              " j=" + std::to_string(j)
+                             ));
+    }
+
+  deallog << "Ok" << std::endl;
+}
+
+
+int main(int argc, char *argv[])
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  // MPILogInitAll log;
+  // test();
+
+  if (Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0)
+    {
+      initlog();
+      test();
+    }
+  else
+    test();
+
+  return 0;
+}
diff --git a/tests/mpi/collective_sparse_matrix_01.mpirun=1.output b/tests/mpi/collective_sparse_matrix_01.mpirun=1.output
new file mode 100644 (file)
index 0000000..6ea1f89
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL::Ok
diff --git a/tests/mpi/collective_sparse_matrix_01.mpirun=3.output b/tests/mpi/collective_sparse_matrix_01.mpirun=3.output
new file mode 100644 (file)
index 0000000..6ea1f89
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL::Ok

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.